├── debian ├── compat ├── docs ├── source │ └── format ├── changelog ├── rules ├── control └── copyright ├── doc ├── Makefile.am ├── reference │ ├── version.xml.in │ ├── meson.build │ ├── i3ipc-glib-docs.xml │ └── Makefile.am └── meson.build ├── test-requirements.txt ├── Makefile.am ├── meson_options.txt ├── examples ├── meson.build └── i3ipc-glib-events.c ├── test ├── test_restart.py ├── test_get_config.py ├── test_get_bindings_modes.py ├── test_leaves.py ├── test_get_marks.py ├── test_window.py ├── test_shutdown_event.py ├── test_ticks.py ├── ipctest.py └── i3.config ├── i3ipc-glib ├── i3ipc-glib.h ├── i3ipc-glib.pc.in ├── i3ipc-enum-types.h.in ├── i3ipc-enum-types.c.in ├── i3ipc-con-private.h ├── Makefile.am.enums ├── meson.build ├── Makefile.am ├── i3ipc-con.h ├── i3ipc-connection.h ├── i3ipc-reply-types.h ├── i3ipc-event-types.h ├── i3ipc-reply-types.c ├── i3ipc-event-types.c └── i3ipc-con.c ├── .clang-format ├── meson.build ├── i3ipc-glib.spec ├── autogen.sh ├── .gitignore ├── configure.ac ├── README.md ├── CHANGELOG.md ├── run-tests.py └── COPYING /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README.md 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = reference 2 | -------------------------------------------------------------------------------- /doc/reference/version.xml.in: -------------------------------------------------------------------------------- 1 | @I3IPC_VERSION@ 2 | -------------------------------------------------------------------------------- /test-requirements.txt: -------------------------------------------------------------------------------- 1 | pytest 2 | enum-compat 3 | yapf 4 | vext.gi 5 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I build/autotools 2 | DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection 3 | SUBDIRS=i3ipc-glib doc 4 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('gtk-doc', type: 'boolean', value: true, description: 'build docs') 2 | option('introspection', type: 'boolean', value: true, description: 'build gir data') 3 | -------------------------------------------------------------------------------- /examples/meson.build: -------------------------------------------------------------------------------- 1 | events_executable = executable( 2 | 'i3ipc-glib-events', 3 | ['i3ipc-glib-events.c', enums[1]], 4 | dependencies: i3ipc, 5 | include_directories: '..' 6 | ) 7 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libi3ipc-glib (0.6.0-1) unstable; urgency=low 2 | 3 | * Bump to version 0.6.0 4 | 5 | -- Alexandre Acebedo Tue, 17 Aug 2015 19:49:42 +0200 6 | -------------------------------------------------------------------------------- /test/test_restart.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | import pytest 3 | 4 | 5 | @pytest.mark.skip(reason='TODO') 6 | class TestRestart(IpcTest): 7 | def test_auto_reconnect(self, i3): 8 | i3.auto_reconnect = True 9 | i3.command('restart') 10 | assert i3.command('nop') 11 | -------------------------------------------------------------------------------- /doc/meson.build: -------------------------------------------------------------------------------- 1 | if get_option('gtk-doc') 2 | gtkdoc = find_program('gtkdoc-scan', required: false) 3 | if not gtkdoc.found() 4 | error('You need to have gtk-doc installed to generate docs. Disable it with `-Dgtk-doc=false` if you don\'t want to build docs') 5 | endif 6 | subdir('reference') 7 | endif 8 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-glib.h: -------------------------------------------------------------------------------- 1 | #ifndef __I3IPC_GLIB_H__ 2 | #define __I3IPC_GLIB_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #endif /* __I3IPC_GLIB_H__ */ 11 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-glib.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: i3ipc-GLib 7 | Description: i3ipc for GLib 8 | Version: @VERSION@ 9 | Libs: -L${libdir} -li3ipc-glib-1.0 10 | Cflags: -I${includedir} 11 | Requires: gobject-2.0 12 | Requires.private: json-glib-1.0 gio-2.0 13 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: google 2 | AllowShortIfStatementsOnASingleLine: false 3 | AllowShortLoopsOnASingleLine: false 4 | AllowShortFunctionsOnASingleLine: None 5 | AllowShortBlocksOnASingleLine: false 6 | AlwaysBreakBeforeMultilineStrings: false 7 | IndentWidth: 4 8 | PointerBindsToType: false 9 | ColumnLimit: 100 10 | SpaceBeforeParens: ControlStatements 11 | IndentCaseLabels: false 12 | -------------------------------------------------------------------------------- /test/test_get_config.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | from gi.repository import i3ipc 3 | import pytest 4 | 5 | 6 | @pytest.mark.skip(reason='TODO') 7 | class TestGetConfig(IpcTest): 8 | def test_get_config(self, i3): 9 | config = i3.get_config() 10 | assert isinstance(config, i3ipc.ConfigReply) 11 | with open('test/i3.config') as f: 12 | assert config.config == f.read() 13 | -------------------------------------------------------------------------------- /test/test_get_bindings_modes.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | import pytest 3 | 4 | 5 | @pytest.mark.skip(reason='TODO') 6 | class TestBindingModes(IpcTest): 7 | def test_binding_modes(self, i3): 8 | binding_modes = i3.get_binding_modes() 9 | assert isinstance(binding_modes, list) 10 | assert len(binding_modes) == 2 11 | assert 'default' in binding_modes 12 | assert 'resize' in binding_modes 13 | -------------------------------------------------------------------------------- /test/test_leaves.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | from gi.repository import i3ipc 3 | 4 | 5 | class TestLeaves(IpcTest): 6 | def test_workspace_leaves(self, i3): 7 | ws_name = self.fresh_workspace() 8 | con1 = self.open_window() 9 | command = i3.command('[id=%s] floating enable' % con1) 10 | con2 = self.open_window() 11 | con3 = self.open_window() 12 | 13 | ws = [w for w in i3.get_tree().workspaces() if w.props.name == ws_name][0] 14 | 15 | assert (len(ws.leaves()) == 3) 16 | -------------------------------------------------------------------------------- /test/test_get_marks.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | from gi.repository import i3ipc 3 | 4 | 5 | class TestGetMarks(IpcTest): 6 | def test_get_marks(self, i3): 7 | self.open_window() 8 | i3.command('mark a') 9 | i3.command('mark --add b') 10 | self.open_window() 11 | i3.command('mark "(╯°□°)╯︵ ┻━┻"') 12 | 13 | marks = i3.get_marks() 14 | assert isinstance(marks, list) 15 | assert len(marks) == 3 16 | assert 'a' in marks 17 | assert 'b' in marks 18 | assert '(╯°□°)╯︵ ┻━┻' in marks 19 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-enum-types.h.in: -------------------------------------------------------------------------------- 1 | /*** BEGIN file-header ***/ 2 | #ifndef __I3IPC_ENUM_TYPES_H__ 3 | #define __I3IPC_ENUM_TYPES_H__ 4 | 5 | #include 6 | 7 | /*** END file-header ***/ 8 | 9 | /*** BEGIN file-production ***/ 10 | /* enumerations from "@filename@" */ 11 | /*** END file-production ***/ 12 | 13 | /*** BEGIN file-tail ***/ 14 | 15 | #endif /* !__I3IPC_ENUM_TYPES_H__ */ 16 | /*** END file-tail ***/ 17 | 18 | /*** BEGIN value-header ***/ 19 | GType @enum_name@_get_type (void) G_GNUC_CONST; 20 | #define I3IPC_TYPE_@ENUMSHORT@ (@enum_name@_get_type()) 21 | 22 | /*** END value-header ***/ 23 | 24 | -------------------------------------------------------------------------------- /test/test_window.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | import pytest 3 | 4 | 5 | @pytest.mark.skip(reason='TODO') 6 | class TestWindow(IpcTest): 7 | event = None 8 | 9 | def on_window(self, i3, e): 10 | self.event = e 11 | i3.main_quit() 12 | 13 | def test_window_event(self, i3): 14 | self.fresh_workspace() 15 | workspaces = i3.get_workspaces() 16 | i3.on('window', self.on_window) 17 | self.open_window() 18 | i3.main(timeout=1) 19 | assert self.event 20 | 21 | def test_marks(self, i3): 22 | ws = self.fresh_workspace() 23 | self.open_window() 24 | i3.command('mark foo') 25 | assert 'foo' in i3.get_tree().find_focused().marks 26 | -------------------------------------------------------------------------------- /examples/i3ipc-glib-events.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void print_change(i3ipcConnection *self, i3ipcWindowEvent *e, gpointer user_data) { 6 | printf("Change : %s\n", e->change); 7 | } 8 | 9 | int main() { 10 | GMainLoop *loop = g_main_loop_new(NULL, FALSE); 11 | i3ipcConnection *conn; 12 | i3ipcCommandReply *cr; 13 | 14 | conn = i3ipc_connection_new(NULL, NULL); 15 | cr = i3ipc_connection_subscribe(conn, I3IPC_EVENT_WINDOW, NULL); 16 | i3ipc_command_reply_free(cr); 17 | 18 | g_object_connect(conn, "signal::window", G_CALLBACK(print_change), NULL, NULL); 19 | 20 | g_main_loop_run(loop); 21 | g_object_unref(conn); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/test_shutdown_event.py: -------------------------------------------------------------------------------- 1 | from threading import Timer 2 | from ipctest import IpcTest 3 | import pytest 4 | 5 | 6 | @pytest.mark.skip(reason='TODO') 7 | class TestShutdownEvent(IpcTest): 8 | events = [] 9 | 10 | def restart_func(t, i3): 11 | i3.command('restart') 12 | 13 | def on_shutdown(self, i3, e): 14 | self.events.append(e) 15 | assert i3._wait_for_socket() 16 | if len(self.events) == 1: 17 | Timer(0.001, self.restart_func, args=(i3, )).start() 18 | elif len(self.events) == 2: 19 | i3.main_quit() 20 | 21 | def test_shutdown_event_reconnect(self, i3): 22 | i3.auto_reconnect = True 23 | self.events = [] 24 | i3.on('shutdown::restart', self.on_shutdown) 25 | Timer(0.001, self.restart_func, args=(i3, )).start() 26 | i3.main(timeout=1) 27 | assert len(self.events) == 2 28 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # See debhelper(7) (uncomment to enable) 3 | # output every command that modifies files on the build system. 4 | #DH_VERBOSE = 1 5 | 6 | # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* 7 | DPKG_EXPORT_BUILDFLAGS = 1 8 | include /usr/share/dpkg/default.mk 9 | 10 | # see FEATURE AREAS in dpkg-buildflags(1) 11 | #export DEB_BUILD_MAINT_OPTIONS = hardening=+all 12 | 13 | # see ENVIRONMENT in dpkg-buildflags(1) 14 | # package maintainers to append CFLAGS 15 | #export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic 16 | # package maintainers to append LDFLAGS 17 | #export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed 18 | export PREFIX=/usr 19 | 20 | # main packaging script based on dh7 syntax 21 | %: 22 | dh $@ 23 | 24 | # debmake generated override targets 25 | # This is example for Cmake (See http://bugs.debian.org/641051 ) 26 | 27 | override_dh_auto_configure: 28 | ./autogen.sh --prefix=/usr 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/test_ticks.py: -------------------------------------------------------------------------------- 1 | from ipctest import IpcTest 2 | from gi.repository import i3ipc 3 | import pytest 4 | 5 | 6 | @pytest.mark.skip(reason='TODO') 7 | class TestTicks(IpcTest): 8 | events = [] 9 | 10 | def on_tick(self, i3, e): 11 | self.events.append(e) 12 | if len(self.events) == 3: 13 | i3.main_quit() 14 | 15 | def test_tick_event(self, i3): 16 | i3.on('tick', self.on_tick) 17 | i3.event_socket_setup() 18 | i3.send_tick() 19 | i3.send_tick('hello world') 20 | while not i3.event_socket_poll(): 21 | pass 22 | i3.event_socket_teardown() 23 | 24 | assert len(self.events) == 3 25 | assert self.events[0].first 26 | assert self.events[0].payload == '' 27 | assert not self.events[1].first 28 | assert self.events[1].payload == '' 29 | assert not self.events[2].first 30 | assert self.events[2].payload == 'hello world' 31 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'i3ipc-glib', 3 | 'c', 4 | version: '2.0.0-rc1', 5 | meson_version: '>=0.46.0' 6 | ) 7 | 8 | gnome = import('gnome') 9 | pkgconfig = import('pkgconfig') 10 | 11 | version_conf = configuration_data() 12 | 13 | i3ipc_version = meson.project_version().split('-')[0] 14 | version_array = i3ipc_version.split('.') 15 | i3ipc_major_version = version_array[0] 16 | 17 | version_conf.set( 18 | 'I3IPC_VERSION', 19 | meson.project_version(), 20 | ) 21 | version_conf.set( 22 | 'I3IPC_MAJOR_VERSION', 23 | i3ipc_major_version.to_int(), 24 | ) 25 | version_conf.set( 26 | 'I3IPC_MINOR_VERSION', 27 | version_array[1].to_int(), 28 | ) 29 | version_conf.set( 30 | 'I3IPC_MICRO_VERSION', 31 | version_array[2].to_int(), 32 | ) 33 | 34 | xcb_dep = dependency('xcb') 35 | json_dep = dependency('json-glib-1.0') 36 | gobject_dep = dependency('gobject-2.0', version: '>=2.38') 37 | gio_dep = dependency('gio-unix-2.0') 38 | glib_dep = dependency('glib-2.0') 39 | 40 | subdir('i3ipc-glib') 41 | subdir('doc') 42 | subdir('examples') 43 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-enum-types.c.in: -------------------------------------------------------------------------------- 1 | /*** BEGIN file-header ***/ 2 | #include "i3ipc-enum-types.h" 3 | /*** END file-header ***/ 4 | 5 | /*** BEGIN file-production ***/ 6 | 7 | /* enumerations from "@filename@" */ 8 | #include "@filename@" 9 | 10 | /*** END file-production ***/ 11 | 12 | /*** BEGIN value-header ***/ 13 | GType 14 | @enum_name@_get_type(void) { 15 | static volatile gsize g_enum_type_id__volatile = 0; 16 | 17 | if (g_once_init_enter (&g_enum_type_id__volatile)) 18 | { 19 | static const G@Type@Value values[] = { 20 | /*** END value-header ***/ 21 | 22 | /*** BEGIN value-production ***/ 23 | { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, 24 | /*** END value-production ***/ 25 | 26 | /*** BEGIN value-tail ***/ 27 | { 0, NULL, NULL } 28 | }; 29 | GType g_enum_type_id; 30 | 31 | g_enum_type_id = 32 | g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); 33 | 34 | g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id); 35 | } 36 | 37 | return g_enum_type_id__volatile; 38 | } 39 | /*** END value-tail ***/ 40 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: libi3ipc-glib 2 | section: utils 3 | Priority: optional 4 | Maintainer: Alexandre Acebedo 5 | Build-Depends: debhelper (>= 9), libjson-glib-dev, libxcb1-dev, gobject-introspection, gtk-doc-tools, libglib2.0-dev, libx11-dev 6 | Standards-Version: 3.9.5 7 | Homepage: http://www.github.com/aacebedo/i3ipc-glib 8 | 9 | Package: libi3ipc-glib 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, ${misc:Depends}, libxcb1, libjson-glib-1.0-0, gobject-introspection, libglib2.0-0 12 | Description: A C interface library to i3wm 13 | i3's interprocess communication (or ipc) is the interface i3wm uses to receive commands from client applications such as i3-msg. It also features a publish/subscribe mechanism for notifying interested parties of window manager events. i3ipc-GLib is a C library for controlling the window manager. This project is intended to be useful in applications such as status line generators, pagers, notification daemons, scripting wrappers, external controllers, dock windows, compositors, config templaters, and for debugging or testing the window manager itself. 14 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-con-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #ifndef __I3IPC_CON_PRIVATE_H__ 22 | #define __I3IPC_CON_PRIVATE_H__ 23 | 24 | #include 25 | 26 | #include "i3ipc-con.h" 27 | #include "i3ipc-connection.h" 28 | 29 | i3ipcCon *i3ipc_con_new(i3ipcCon *parent, JsonObject *data, i3ipcConnection *conn); 30 | 31 | #endif /* __I3IPC_CON_PRIVATE_H__ */ 32 | -------------------------------------------------------------------------------- /doc/reference/meson.build: -------------------------------------------------------------------------------- 1 | glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix') 2 | glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') 3 | 4 | configure_file( 5 | input : 'version.xml.in', 6 | output : 'version.xml', 7 | configuration : version_conf, 8 | ) 9 | 10 | i3ipc_shared_link = declare_dependency( 11 | link_with: i3ipc_lib.get_shared_lib(), 12 | dependencies: deps 13 | ) 14 | 15 | gnome.gtkdoc( 16 | 'i3ipc', 17 | src_dir: join_paths(meson.source_root(), 'i3ipc-glib'), 18 | dependencies: [ 19 | glib_dep, 20 | gobject_dep, 21 | i3ipc_shared_link 22 | ], 23 | mkdb_args: [ 24 | '--output-format=xml', 25 | '--name-space=i3ipc', 26 | ], 27 | scan_args: '--deprecated-guards="I3IPC_DISABLE_DEPRECATED"', 28 | gobject_typesfile: join_paths(meson.current_build_dir(), 'i3ipc.types'), 29 | fixxref_args: [ 30 | '--extra-dir=@0@'.format(join_paths(glib_docpath, 'gobject')), 31 | '--extra-dir=@0@'.format(join_paths(glib_docpath, 'gio')), 32 | '--extra-dir=@0@'.format(glib_docpath), 33 | ], 34 | main_sgml: 'i3ipc-glib-docs.xml', 35 | ignore_headers: [ 36 | 'i3ipc-glib.h', 37 | 'i3ipc-con-private.h' 38 | ], 39 | install: true, 40 | ) 41 | -------------------------------------------------------------------------------- /i3ipc-glib.spec: -------------------------------------------------------------------------------- 1 | Summary: A C interface library to i3wm 2 | Name: i3ipc-glib 3 | Version: 1.0.1 4 | Release: 1%{?dist} 5 | Source0: %{name}-%{version}.tar.gz 6 | License: GPL v3 7 | URL: https://github.com/altdesktop/i3ipc-glib 8 | 9 | BuildRequires: libtool 10 | BuildRequires: libX11-devel 11 | BuildRequires: libxcb-devel 12 | BuildRequires: gobject-introspection-devel 13 | BuildRequires: glib2-devel 14 | BuildRequires: json-glib-devel 15 | BuildRequires: gtk-doc 16 | 17 | %if 0%{?suse_version} >= 1500 18 | Requires: libxcb1 19 | Requires: libjson-glib-1_0-0 20 | Requires: libglib-2_0-0 21 | %else 22 | Requires: libxcb 23 | Requires: json-glib 24 | Requires: glib2 25 | %endif 26 | Requires: gobject-introspection 27 | 28 | %description 29 | A C interface library to i3wm. 30 | 31 | 32 | %prep 33 | %setup -q 34 | 35 | 36 | %build 37 | ./autogen.sh --prefix=%{_prefix} --libdir=%{_libdir} 38 | make 39 | 40 | 41 | %install 42 | %make_install 43 | 44 | 45 | %files 46 | %doc COPYING 47 | %doc README.md 48 | %{_includedir}/i3ipc-glib/i3ipc*.h 49 | %{_libdir}/girepository-1.0/i3ipc-1.0.typelib 50 | %{_libdir}/libi3ipc-glib-1.0.* 51 | %{_libdir}/pkgconfig/i3ipc-glib-1.0.pc 52 | %{_datadir}/gir-1.0/i3ipc-1.0.gir 53 | 54 | 55 | %changelog 56 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Run this to generate all the initial makefiles, etc. 3 | 4 | test -n "$srcdir" || srcdir=`dirname "$0"` 5 | test -n "$srcdir" || srcdir=. 6 | 7 | olddir=`pwd` 8 | 9 | cd $srcdir 10 | PROJECT=i3ipc-GLib 11 | TEST_TYPE=-f 12 | FILE=i3ipc-glib/i3ipc-glib.h 13 | 14 | test $TEST_TYPE $FILE || { 15 | echo "You must run this script in the top-level $PROJECT directory" 16 | exit 1 17 | } 18 | 19 | GTKDOCIZE=`which gtkdocize` 20 | if test -z $GTKDOCIZE; then 21 | echo "*** No GTK-Doc found, please install it ***" 22 | exit 1 23 | fi 24 | 25 | AUTORECONF=`which autoreconf` 26 | if test -z $AUTORECONF; then 27 | echo "*** No autoreconf found, please install it ***" 28 | exit 1 29 | fi 30 | 31 | # NOCONFIGURE is used by gnome-common 32 | if test -z "$NOCONFIGURE"; then 33 | if test -z "$*"; then 34 | echo "I am going to run ./configure with no arguments - if you wish " 35 | echo "to pass any to it, please specify them on the $0 command line." 36 | fi 37 | fi 38 | 39 | rm -rf autom4te.cache 40 | 41 | gtkdocize || exit $? 42 | autoreconf --force --install --verbose || exit $? 43 | 44 | cd "$olddir" 45 | test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" 46 | -------------------------------------------------------------------------------- /i3ipc-glib/Makefile.am.enums: -------------------------------------------------------------------------------- 1 | # Rules for generating enumeration types using glib-mkenums 2 | # 3 | # Define: 4 | # glib_enum_h = header template file 5 | # glib_enum_c = source template file 6 | # glib_enum_headers = list of headers to parse 7 | # 8 | # before including Makefile.am.enums. You will also need to have 9 | # the following targets already defined: 10 | # 11 | # CLEANFILES 12 | # DISTCLEANFILES 13 | # BUILT_SOURCES 14 | # EXTRA_DIST 15 | # 16 | # Author: Emmanuele Bassi 17 | 18 | enum_tmpl_h=$(glib_enum_h:.h=.h.in) 19 | enum_tmpl_c=$(glib_enum_c:.c=.c.in) 20 | 21 | CLEANFILES += stamp-enum-types 22 | DISTCLEANFILES += $(glib_enum_h) $(glib_enum_c) 23 | BUILT_SOURCES += $(glib_enum_h) $(glib_enum_c) 24 | EXTRA_DIST += $(srcdir)/$(enum_tmpl_h) $(srcdir)/$(enum_tmpl_c) 25 | 26 | stamp-enum-types: $(glib_enum_headers) $(srcdir)/$(enum_tmpl_h) 27 | $(AM_V_GEN)$(GLIB_MKENUMS) \ 28 | --template $(srcdir)/$(enum_tmpl_h) \ 29 | $(glib_enum_headers) > xgen-eh \ 30 | && (cmp -s xgen-eh $(glib_enum_h) || cp -f xgen-eh $(glib_enum_h)) \ 31 | && rm -f xgen-eh \ 32 | && echo timestamp > $(@F) 33 | 34 | $(glib_enum_h): stamp-enum-types 35 | @true 36 | 37 | $(glib_enum_c): $(glib_enum_h) $(srcdir)/$(enum_tmpl_c) 38 | $(AM_V_GEN)$(GLIB_MKENUMS) \ 39 | --template $(srcdir)/$(enum_tmpl_c) \ 40 | $(glib_enum_headers) > xgen-ec \ 41 | && cp -f xgen-ec $(glib_enum_c) \ 42 | && rm -f xgen-ec 43 | -------------------------------------------------------------------------------- /test/ipctest.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen 2 | import pytest 3 | from gi.repository import i3ipc 4 | import math 5 | from random import random 6 | from time import sleep 7 | 8 | 9 | class IpcTest: 10 | timeout_thread = None 11 | i3_conn = None 12 | 13 | @pytest.fixture(scope='class') 14 | def i3(self): 15 | process = Popen(['/usr/bin/i3', '-c', 'test/i3.config']) 16 | # wait for i3 to start up 17 | tries = 0 18 | 19 | while True: 20 | try: 21 | IpcTest.i3_conn = i3ipc.Connection.new() 22 | break 23 | except Exception: 24 | tries += 1 25 | 26 | if tries > 500: 27 | raise Exception('could not start i3') 28 | sleep(0.01) 29 | 30 | yield IpcTest.i3_conn 31 | process.kill() 32 | IpcTest.i3_conn = None 33 | 34 | def open_window(self): 35 | i3 = IpcTest.i3_conn 36 | assert i3 37 | 38 | result = i3.command('open') 39 | return result[0]._id 40 | 41 | def fresh_workspace(self): 42 | i3 = IpcTest.i3_conn 43 | assert i3 44 | 45 | workspaces = i3.get_workspaces() 46 | while True: 47 | new_name = str(math.floor(random() * 100000)) 48 | if not any(w for w in workspaces if w.name == new_name): 49 | i3.command('workspace %s' % new_name) 50 | return new_name 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Autotools 2 | /configure 3 | /stamp-h1 4 | /libtool 5 | /gtk-doc.make 6 | /**/Makefile 7 | /**/Makefile.in 8 | /aclocal.m4 9 | /autom4te.cache 10 | /config.h 11 | /config.h.in 12 | /config.h.in~ 13 | /config.log 14 | /config.status 15 | /build/ar-lib 16 | /build/compile 17 | /build/config.guess 18 | /build/config.sub 19 | /build/depcomp 20 | /build/install-sh 21 | /build/ltmain.sh 22 | /build/missing 23 | /build/autotools/libtool.m4 24 | /build/autotools/ltoptions.m4 25 | /build/autotools/ltsugar.m4 26 | /build/autotools/ltversion.m4 27 | /build/autotools/lt~obsolete.m4 28 | 29 | # Docs 30 | /build/autotools/gtk-doc.m4 31 | /doc/reference/html/**/* 32 | /doc/reference/xml/**/* 33 | /doc/reference/version.xml 34 | 35 | # Project-specific 36 | /i3ipc-glib/.deps/**/* 37 | /i3ipc-glib/.libs/**/* 38 | /i3ipc-*.tar.gz 39 | /i3ipc-glib/i3ipc-glib-1.0.pc 40 | /i3ipc-glib/i3ipc-glib.pc 41 | /i3ipc-glib/i3ipc-1.0.gir 42 | /i3ipc-glib/i3ipc-1.0.typelib 43 | /i3ipc-glib/stamp-enum-types 44 | /i3ipc-glib/i3ipc-enum-types.[ch] 45 | 46 | # ASD 47 | .flagged 48 | 49 | # Editor 50 | *.swl 51 | *.swm 52 | *.swn 53 | *.swo 54 | *.swp 55 | .clang_complete 56 | 57 | # Object files 58 | *.la 59 | *.lo 60 | *.o 61 | *.ko 62 | *.obj 63 | *.elf 64 | 65 | # Libraries 66 | *.lib 67 | *.a 68 | 69 | # Shared objects (inc. Windows DLLs) 70 | *.dll 71 | *.so 72 | *.so.* 73 | *.dylib 74 | 75 | # Executables 76 | *.exe 77 | *.out 78 | *.app 79 | *.i*86 80 | *.x86_64 81 | *.hex 82 | 83 | # Meson 84 | mesonbuild 85 | 86 | # Tests 87 | .pytest_cache 88 | mesonbuild-test 89 | __pycache__ 90 | env 91 | *.pyc 92 | -------------------------------------------------------------------------------- /doc/reference/i3ipc-glib-docs.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | ]> 8 | 9 | 10 | i3ipc-glib Reference Manual 11 | 12 | for i3ipc-glib &version; 13 | The latest version of this documentation can be found on-line at 14 | http://dubstepdish.com/i3ipc-glib/. 15 | 16 | 17 | 18 | 19 | Data Types 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | Object Hierarchy 28 | 29 | 30 | 31 | API Index 32 | 33 | 34 | 35 | Index of deprecated API 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | m4_define([i3ipc_major_version], [1]) 2 | m4_define([i3ipc_minor_version], [0]) 3 | m4_define([i3ipc_micro_version], [1]) 4 | 5 | m4_define([i3ipc_version], [i3ipc_major_version.i3ipc_minor_version.i3ipc_micro_version]) 6 | 7 | AC_PREREQ(2.69) 8 | 9 | AC_INIT([i3ipc], [i3ipc_version], [tony@dubstepdish.com]) 10 | 11 | AC_CONFIG_AUX_DIR([build]) 12 | AC_CONFIG_MACRO_DIR([build/autotools]) 13 | AC_CONFIG_SRCDIR([i3ipc-glib/i3ipc-glib.h]) 14 | AC_CONFIG_HEADER([config.h]) 15 | 16 | # Checks for programs. 17 | AC_PROG_CC 18 | AC_PROG_INSTALL 19 | 20 | # Checks for libraries. 21 | PKG_CHECK_MODULES([xcb], [xcb]) 22 | PKG_CHECK_MODULES([json], [json-glib-1.0]) 23 | PKG_CHECK_MODULES([gobject], [gobject-2.0 >= 2.32]) 24 | PKG_CHECK_MODULES([gio], [gio-2.0]) 25 | 26 | # Checks for header files. 27 | AC_CHECK_HEADERS([fcntl.h sys/socket.h]) 28 | 29 | # Checks for typedefs, structures, and compiler characteristics. 30 | AC_C_CONST 31 | AC_C_INLINE 32 | AC_TYPE_SIZE_T 33 | 34 | # Checks for library functions. 35 | AC_FUNC_MALLOC 36 | AC_CHECK_FUNCS([memset socket strerror]) 37 | 38 | AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability]) 39 | AM_PATH_GLIB_2_0 40 | AM_PROG_AR 41 | AM_SILENT_RULES([yes]) 42 | LT_INIT 43 | 44 | # Versioning 45 | I3IPC_MAJOR_VERSION=i3ipc_major_version 46 | I3IPC_MINOR_VERSION=i3ipc_minor_version 47 | I3IPC_MICRO_VERSION=i3ipc_micro_version 48 | I3IPC_VERSION=i3ipc_version 49 | AC_SUBST(I3IPC_MAJOR_VERSION) 50 | AC_SUBST(I3IPC_MINOR_VERSION) 51 | AC_SUBST(I3IPC_MICRO_VERSION) 52 | AC_SUBST(I3IPC_VERSION) 53 | 54 | GOBJECT_INTROSPECTION_CHECK([1.32.0]) 55 | 56 | # Check for gtk-doc 57 | GTK_DOC_CHECK([1.14],[--flavour no-tmpl]) 58 | 59 | AC_CONFIG_FILES([ 60 | Makefile 61 | i3ipc-glib/Makefile 62 | i3ipc-glib/i3ipc-glib.pc 63 | doc/Makefile 64 | doc/reference/Makefile 65 | doc/reference/version.xml 66 | ]) 67 | 68 | AC_OUTPUT 69 | -------------------------------------------------------------------------------- /i3ipc-glib/meson.build: -------------------------------------------------------------------------------- 1 | configuration_inc = include_directories('..') 2 | 3 | headers = [ 4 | 'i3ipc-con.h', 5 | 'i3ipc-glib.h', 6 | 'i3ipc-reply-types.h', 7 | 'i3ipc-event-types.h', 8 | 'i3ipc-connection.h' 9 | ] 10 | 11 | i3ipc_sources = [ 12 | 'i3ipc-con.c', 13 | 'i3ipc-connection.c', 14 | 'i3ipc-reply-types.c', 15 | 'i3ipc-event-types.c' 16 | ] 17 | 18 | deps = [ 19 | xcb_dep, 20 | json_dep, 21 | gobject_dep, 22 | gio_dep, 23 | glib_dep 24 | ] 25 | 26 | install_headers( 27 | headers, 28 | install_dir: join_paths(get_option('includedir'), 'i3ipc-glib') 29 | ) 30 | 31 | enums = gnome.mkenums_simple( 32 | 'i3ipc-enum-types', 33 | sources: headers, 34 | install_header: true, 35 | install_dir: join_paths(get_option('includedir'), 'i3ipc-glib') 36 | ) 37 | 38 | i3ipc_lib = both_libraries( 39 | 'i3ipc-glib', 40 | i3ipc_sources, enums, 41 | dependencies: deps, 42 | version: i3ipc_version, 43 | include_directories: configuration_inc, 44 | install: true 45 | ) 46 | 47 | i3ipc = declare_dependency( 48 | link_with: i3ipc_lib.get_shared_lib(), 49 | dependencies: deps 50 | ) 51 | 52 | if get_option('introspection') 53 | introspection_dep = dependency('gobject-introspection-1.0', required: false) 54 | if not introspection_dep.found() 55 | error('You need to have gobject-introspection installed to generate Gir data. Disable it with `-Dintrospection=false` if you don\'t want to build it') 56 | endif 57 | 58 | gnome.generate_gir( 59 | i3ipc_lib, 60 | sources: [ 61 | enums, 62 | 'i3ipc-connection.c', 63 | 'i3ipc-connection.h', 64 | 'i3ipc-con.c', 65 | 'i3ipc-con.h', 66 | 'i3ipc-reply-types.c', 67 | 'i3ipc-reply-types.h', 68 | 'i3ipc-event-types.c', 69 | 'i3ipc-event-types.h' 70 | ], 71 | nsversion: i3ipc_major_version + '.0', 72 | namespace: 'i3ipc', 73 | includes: ['GObject-2.0'], 74 | install: true 75 | ) 76 | endif 77 | 78 | pkgconfig.generate( 79 | libraries: i3ipc_lib, 80 | subdirs: 'i3ipc-glib', 81 | version: meson.project_version(), 82 | name: 'i3ipc-glib', 83 | filebase: 'i3ipc-glib', 84 | description: 'A library for controling i3wm', 85 | requires: ['gobject-2.0'], 86 | requires_private: 'gio-2.0', 87 | ) 88 | -------------------------------------------------------------------------------- /i3ipc-glib/Makefile.am: -------------------------------------------------------------------------------- 1 | # preamble 2 | 3 | EXTRA_DIST= 4 | BUILT_SOURCES= 5 | DISTCLEANFILES= 6 | CLEANFILES= 7 | lib_LTLIBRARIES= 8 | NULL= 9 | 10 | AM_CPPFLAGS = \ 11 | $(xcb_CFLAGS) \ 12 | $(json_CFLAGS) \ 13 | $(gobject_CFLAGS) \ 14 | $(gio_CFLAGS) \ 15 | $(NULL) 16 | 17 | AM_CFLAGS = -std=gnu99 -Wall 18 | 19 | source_h = \ 20 | $(top_srcdir)/i3ipc-glib/i3ipc-con.h \ 21 | $(top_srcdir)/i3ipc-glib/i3ipc-event-types.h \ 22 | $(top_srcdir)/i3ipc-glib/i3ipc-reply-types.h \ 23 | $(top_srcdir)/i3ipc-glib/i3ipc-connection.h \ 24 | $(NULL) 25 | 26 | source_h_private = \ 27 | $(top_srcdir)/i3ipc-glib/i3ipc-con-private.h \ 28 | $(NULL) 29 | 30 | source_c = \ 31 | i3ipc-con.c \ 32 | i3ipc-event-types.c \ 33 | i3ipc-reply-types.c \ 34 | i3ipc-connection.c \ 35 | $(NULL) 36 | 37 | # glib-mkenums rules 38 | glib_enum_h = i3ipc-enum-types.h 39 | glib_enum_c = i3ipc-enum-types.c 40 | glib_enum_headers = $(source_h) 41 | include $(top_srcdir)/i3ipc-glib/Makefile.am.enums 42 | 43 | lib_LTLIBRARIES += libi3ipc-glib-1.0.la 44 | libi3ipc_glib_1_0_la_LIBADD = $(xcb_LIBS) $(json_LIBS) $(gobject_LIBS) $(gio_LIBS) 45 | libi3ipc_glib_1_0_la_SOURCES = $(source_c) $(source_h) $(source_h_private) $(BUILT_SOURCES) 46 | 47 | i3ipcincludedir = $(includedir)/i3ipc-glib 48 | i3ipcinclude_DATA = \ 49 | $(source_h) \ 50 | $(top_srcdir)/i3ipc-glib/i3ipc-enum-types.h \ 51 | $(top_srcdir)/i3ipc-glib/i3ipc-glib.h \ 52 | $(NULL) 53 | 54 | EXTRA_DIST += i3ipc-glib.h 55 | 56 | pcfiles = i3ipc-glib-1.0.pc 57 | 58 | i3ipc-glib-1.0.pc: i3ipc-glib.pc 59 | $(AM_V_GEN)cp -f $< $@ 60 | 61 | pkgconfig_DATA = $(pcfiles) 62 | pkgconfigdir = $(libdir)/pkgconfig 63 | CLEANFILES += $(pcfiles) 64 | EXTRA_DIST += i3ipc-glib.pc.in 65 | 66 | -include $(INTROSPECTION_MAKEFILE) 67 | INTROSPECTION_GIRS = i3ipc_1_0_gir 68 | INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir) --warn-all 69 | INTROSPECTION_COMPILER_ARGS = 70 | 71 | if HAVE_INTROSPECTION 72 | INTROSPECTION_GIRS += i3ipc-1.0.gir 73 | 74 | i3ipc-1.0.gir: libi3ipc-glib-1.0.la 75 | i3ipc_1_0_gir_INCLUDES = GObject-2.0 76 | i3ipc_1_0_gir_CFLAGS = $(AM_CPPFLAGS) 77 | i3ipc_1_0_gir_PACKAGES = 78 | i3ipc_1_0_gir_LIBS = libi3ipc-glib-1.0.la 79 | i3ipc_1_0_gir_FILES = $(source_h) $(source_c) 80 | i3ipc_1_0_gir_NAMESPACE = i3ipc 81 | i3ipc_1_0_gir_SCANNERFLAGS = --warn-all --pkg-export i3ipc-1.0 --c-include "i3ipc-glib/i3ipc-glib.h" 82 | 83 | girdir = $(datadir)/gir-1.0 84 | gir_DATA = i3ipc-1.0.gir 85 | 86 | typelibdir = $(libdir)/girepository-1.0 87 | typelib_DATA = i3ipc-1.0.typelib 88 | 89 | CLEANFILES += $(gir_DATA) $(typelib_DATA) $(BUILT_SOURCES) 90 | endif 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # i3ipc-GLib 2 | 3 | A C interface library to [i3wm](http://i3wm.org). 4 | 5 | ## About 6 | 7 | i3's interprocess communication (or [ipc](http://i3wm.org/docs/ipc.html)) is the interface i3wm uses to receive [commands](http://i3wm.org/docs/userguide.html#_list_of_commands) from client applications such as `i3-msg`. It also features a publish/subscribe mechanism for notifying interested parties of window manager events. 8 | 9 | i3ipc-GLib is a C library for controlling the window manager. This project is intended to be useful in applications such as status line generators, pagers, notification daemons, scripting wrappers, external controllers, dock windows, compositors, config templaters, and for debugging or testing the window manager itself. 10 | 11 | The latest documentation can be found online [here](http://dubstepdish.com/i3ipc-glib). 12 | 13 | [Chat](https://discord.gg/UdbXHVX) 14 | 15 | ### Projects using i3ipc-GLib 16 | 17 | * [j4status](https://github.com/sardemff7/j4status) - shows the focused window in the status line. 18 | * [xfce4-i3-workspaces-plugin](https://github.com/denesb/xfce4-i3-workspaces-plugin) - workspaces plugin for using xfce4 with i3wm 19 | * [i3-easyfocus](https://github.com/cornerman/i3-easyfocus) - focus and select windows in i3 20 | 21 | ## Installation 22 | 23 | Check the [releases](https://github.com/acrisci/i3ipc-glib/releases) page or your package manager for a package for your distro. Additional packages are available upon request. 24 | 25 | Building the library requires [autotools](https://en.wikipedia.org/wiki/GNU_build_system). Install the project with: 26 | 27 | ```shell 28 | ./autogen.sh # --prefix=/usr might be required 29 | make 30 | sudo make install 31 | ``` 32 | 33 | The following packages are required for building i3-ipc: 34 | 35 | * libxcb and xcb-proto 36 | * glib >= 2.32 37 | * gobject-introspection (optional for bindings) 38 | * json-glib >= 0.14 39 | * gtk-doc-tools 40 | 41 | ## Example 42 | 43 | The i3ipc connection class extends from [GObject](https://developer.gnome.org/gobject/stable/). 44 | 45 | ```C 46 | #include 47 | #include 48 | 49 | gint main() { 50 | i3ipcConnection *conn; 51 | gchar *reply; 52 | 53 | conn = i3ipc_connection_new(NULL, NULL); 54 | 55 | reply = i3ipc_connection_message(conn, I3IPC_MESSAGE_TYPE_COMMAND, "focus left", NULL); 56 | 57 | g_printf("Reply: %s\n", reply); 58 | 59 | g_free(reply); 60 | g_object_unref(conn); 61 | 62 | return 0; 63 | } 64 | ``` 65 | 66 | Compile with `gcc -o example example.c $(pkg-config --libs --cflags i3ipc-glib-1.0)`. 67 | 68 | ## Contributing 69 | 70 | Patches are welcome by pull request to fix bugs and add features. 71 | 72 | ### Task List 73 | 74 | Here is a list of tasks that could be done. 75 | 76 | - [ ] Async commands 77 | 78 | ## License 79 | 80 | This work is available under the GNU General Public License (See COPYING). 81 | 82 | Copyright © 2014, Tony Crisci 83 | 84 | All rights reserved. 85 | -------------------------------------------------------------------------------- /doc/reference/Makefile.am: -------------------------------------------------------------------------------- 1 | # This is a blank Makefile.am for using gtk-doc. 2 | # Copy this to your project's API docs directory and modify the variables to 3 | # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples 4 | # of using the various options. 5 | 6 | # The name of the module, e.g. 'glib'. 7 | DOC_MODULE = i3ipc-glib 8 | 9 | # The top-level XML file. You can change this if you want to. 10 | DOC_MAIN_SGML_FILE = $(DOC_MODULE)-docs.xml 11 | 12 | # The directory containing the source code. Relative to $(srcdir). 13 | # gtk-doc will search all .c & .h files beneath here for inline comments 14 | # documenting the functions and macros. 15 | # e.g. DOC_SOURCE_DIR=../../../gtk 16 | DOC_SOURCE_DIR = ../../i3ipc-glib 17 | 18 | # Extra options to pass to gtkdoc-scangobj. Not normally needed. 19 | SCANGOBJ_OPTIONS = 20 | 21 | # Extra options to supply to gtkdoc-scan. 22 | # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" 23 | SCAN_OPTIONS = --deprecated-guards="I3IPC_DISABLE_DEPRECATED" 24 | 25 | # Extra options to supply to gtkdoc-mkdb. 26 | # e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml 27 | MKDB_OPTIONS = --sgml-mode --output-format=xml --name-space=i3ipc 28 | 29 | # Extra options to supply to gtkdoc-mktmpl 30 | # e.g. MKTMPL_OPTIONS=--only-section-tmpl 31 | MKTMPL_OPTIONS = 32 | 33 | # Extra options to supply to gtkdoc-fixref. Not normally needed. 34 | # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html 35 | FIXXREF_OPTIONS = \ 36 | --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/glib \ 37 | --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gobject \ 38 | --extra-dir=$(GLIB_PREFIX)/share/gtk-doc/html/gio 39 | 40 | # Used for dependencies. The docs will be rebuilt if any of these change. 41 | # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h 42 | # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c 43 | HFILE_GLOB = $(top_srcdir)/i3ipc-glib/*.h $(top_builddir)/i3ipc-glib/*.h 44 | CFILE_GLOB = $(top_srcdir)/i3ipc-glib/*.c 45 | 46 | # Header files to ignore when scanning. 47 | # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h 48 | IGNORE_HFILES = \ 49 | i3ipc-con-private.h \ 50 | i3ipc-enum-types.h \ 51 | i3ipc-glib.h 52 | 53 | EXTRA_HFILES = 54 | 55 | # Images to copy into HTML directory. 56 | # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png 57 | HTML_IMAGES = 58 | 59 | # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). 60 | # e.g. content_files=running.sgml building.sgml changes-2.0.sgml 61 | content_files = \ 62 | version.xml 63 | 64 | # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded 65 | # These files must be listed here *and* in content_files 66 | # e.g. expand_content_files=running.sgml 67 | expand_content_files = 68 | 69 | # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. 70 | # Only needed if you are using gtkdoc-scangobj to dynamically query widget 71 | # signals and properties. 72 | # e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) 73 | # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) 74 | 75 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) $(gobject_CFLAGS) 76 | GTKDOC_LIBS = $(top_builddir)/i3ipc-glib/libi3ipc-glib-1.0.la $(gobject_LIBS) 77 | 78 | # This includes the standard gtk-doc make rules, copied by gtkdocize. 79 | include $(top_srcdir)/gtk-doc.make 80 | 81 | EXTRA_DIST += version.xml.in 82 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-con.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #ifndef __I3IPC_CON_H__ 22 | #define __I3IPC_CON_H__ 23 | 24 | #include 25 | 26 | /** 27 | * SECTION: i3ipc-con 28 | * @short_description: A node in the i3 window container tree, including 29 | * outputs, workspaces, split containers, and top-level windows (leaves). 30 | * 31 | * #i3ipcCon is a node in the i3 window container tree. Cons are created by the 32 | * #i3ipcConnection for queries and on events. This class contains properties 33 | * of the window in the i3 tree. Containers include outputs, workspaces, split 34 | * containers, and top-level windows (leaves). You can use the class methods to 35 | * query containers within the given container based on certain window 36 | * properties, retrieve all the leaves under the container, or execute commands 37 | * in the context of the container. 38 | */ 39 | 40 | #define I3IPC_TYPE_CON (i3ipc_con_get_type()) 41 | #define I3IPC_CON(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), I3IPC_TYPE_CON, i3ipcCon)) 42 | #define I3IPC_IS_CON(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), I3IPC_TYPE_CON)) 43 | #define I3IPC_CON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), I3IPC_TYPE_CON, i3ipcConClass)) 44 | #define I3IPC_IS_CON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), I3IPC_TYPE_CON)) 45 | #define I3IPC_CON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), I3IPC_TYPE_CON, i3ipcConClass)) 46 | 47 | #define I3IPC_TYPE_RECT (i3ipc_rect_get_type()) 48 | 49 | typedef struct _i3ipcRect i3ipcRect; 50 | 51 | typedef struct _i3ipcCon i3ipcCon; 52 | typedef struct _i3ipcConClass i3ipcConClass; 53 | typedef struct _i3ipcConPrivate i3ipcConPrivate; 54 | 55 | /** 56 | * i3ipcRect: 57 | * @x: 58 | * @y: 59 | * @width: 60 | * @height: 61 | * 62 | * An #i3ipcRect descrites the extents of a container. 63 | */ 64 | struct _i3ipcRect { 65 | gint x; 66 | gint y; 67 | gint width; 68 | gint height; 69 | }; 70 | 71 | i3ipcRect *i3ipc_rect_copy(i3ipcRect *rect); 72 | void i3ipc_rect_free(i3ipcRect *rect); 73 | GType i3ipc_rect_get_type(void); 74 | 75 | struct _i3ipcCon { 76 | GObject parent_instance; 77 | 78 | /* instance members */ 79 | i3ipcConPrivate *priv; 80 | }; 81 | 82 | struct _i3ipcConClass { 83 | GObjectClass parent_class; 84 | 85 | /* class members */ 86 | }; 87 | 88 | /* used by I3IPC_TYPE_CON */ 89 | GType i3ipc_con_get_type(void); 90 | 91 | /* Method definitions */ 92 | 93 | const GList *i3ipc_con_get_nodes(i3ipcCon *self); 94 | 95 | const GList *i3ipc_con_get_floating_nodes(i3ipcCon *self); 96 | 97 | i3ipcCon *i3ipc_con_root(i3ipcCon *self); 98 | 99 | GList *i3ipc_con_descendents(i3ipcCon *self); 100 | 101 | GList *i3ipc_con_leaves(i3ipcCon *self); 102 | 103 | const gchar *i3ipc_con_get_name(i3ipcCon *self); 104 | 105 | void i3ipc_con_command(i3ipcCon *self, const gchar *command, GError **err); 106 | 107 | void i3ipc_con_command_children(i3ipcCon *self, const gchar *command, GError **err); 108 | 109 | GList *i3ipc_con_workspaces(i3ipcCon *self); 110 | 111 | i3ipcCon *i3ipc_con_find_focused(i3ipcCon *self); 112 | 113 | i3ipcCon *i3ipc_con_find_by_id(i3ipcCon *self, const gulong con_id); 114 | 115 | i3ipcCon *i3ipc_con_find_by_window(i3ipcCon *self, const guint window_id); 116 | 117 | GList *i3ipc_con_find_named(i3ipcCon *self, const gchar *pattern, GError **err); 118 | 119 | GList *i3ipc_con_find_classed(i3ipcCon *self, const gchar *pattern, GError **err); 120 | 121 | GList *i3ipc_con_find_marked(i3ipcCon *self, const gchar *pattern, GError **err); 122 | 123 | i3ipcCon *i3ipc_con_workspace(i3ipcCon *self); 124 | 125 | i3ipcCon *i3ipc_con_scratchpad(i3ipcCon *self); 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog - i3ipc-GLib 2 | 3 | ## Version 1.0.1 4 | 5 | This release adds bugfixes and breaking changes. 6 | 7 | * Fix memory leak in i3ipcCon (#7) 8 | * Change window id type to uint (breaking) (#9) 9 | * Add `i3ipc_connection_main_with_context` (#13) 10 | * Add `window_role` property (#14) 11 | * Fix `i3ipc_con_descendents` memory leak (#15) 12 | * Add support for `GET_CONFIG` i3ipc message. (#29) 13 | 14 | ## Version 0.6.0 15 | 16 | This release adds two new container properties. 17 | 18 | * con "focus" property is a list of con ids that represents the focus stack of child nodes. 19 | * con "deco_rect" property is the coordinates of the window decoration inside its container. 20 | 21 | ## Version 0.5.0 22 | 23 | This release adds the new `binding` event on the i3ipcConnection and some other bugfixes and features. 24 | 25 | * Add the `binding::run` event. This event is triggered when bindings run because of some user action. 26 | * Add the con `scratchpad` method. This method finds the i3 scratchpad workspace container. 27 | * Bugfix: fix bad leaf check in the con `descendents` method that would cause it to ignore some floating nodes. 28 | 29 | ## Version 0.4.0 30 | 31 | This release adds some missing properties on the container and an abstraction to the GLib main loop. 32 | 33 | * Add the con "mark" property 34 | * Add the con "fullscreen_mode" property 35 | * Implement con method `find_marked` - finds containers that have a mark that matches a pattern 36 | * Add the connection `main` and `main_quit` methods for scripting 37 | 38 | ## Version 0.3.1 39 | 40 | This minor release includes bugfixes and compatability fixes with the latest stable version of i3. Some new methods and a property on the con object have been added as well. 41 | 42 | *This is the first version to distribute a debian package (others available by request)* 43 | 44 | * Bugfix: con methods collect floating descendents 45 | * Bugfix: support con "type" for i3 stable (member type has changed in dev version) 46 | * Implement con floating-nodes property 47 | * Implement con method find_by_id - finds a container with the i3 con id 48 | * Implement con method find_by_window - finds a container with xcb window id 49 | 50 | ## Version 0.3.0 51 | 52 | This release adds more useful container features for targetted use cases and minor bugfixes. 53 | 54 | * Implement con_find_named method - finds containers via regexp 55 | * Implement con_find_classed method - finds containers via regexp with WM_CLASS 56 | * Implement con_leaves method - finds top-level windows 57 | * Implement con window_class property - WM_CLASS as reported by the ipc 58 | * Bugfix: children cons keep a reference on their parent 59 | 60 | ## Version 0.2.0 61 | 62 | This release contains features that make scripting more expressive and powerful and major bugfixes related to language bindings. 63 | 64 | * Bugfix: copy functions make deep copeies (fixes all gjs issues) 65 | * GLib required version reduced to 2.32 (builds on Debian Wheezy) 66 | * Added support for gtk-doc generation 67 | * Detailed ipc signals allow for event filtering based on change 68 | * con_command method - executes a command in the context of a container 69 | * con_command_children method - executes a command in the context of container child nodes 70 | * con_workspaces method - collects the workspaces of a tree 71 | * con_find_focused method - finds a focused container in a container 72 | * con_workspace method - finds the closest workspace 73 | 74 | ## Version 0.1.2 75 | 76 | This is a minor bugfix release. 77 | 78 | * Allow `i3ipc_connection_on` to connect to non-ipc events 79 | 80 | ## Version 0.1.1 81 | 82 | This release contains a number of small bugfixes and feature enhancements. 83 | 84 | * Add `const` qualifier to `*gchar` command and query parameters and transfer-none accessors 85 | * move `i3ipc_con_new` constructor out of the public API 86 | * Move Json-GLib and Gio libraries `Requires` to `Requires.private` in the pkg-config and remove them from the gir/typelib 87 | * New `ipc_shutdown` signal is emitted on the Connection when ipc shutdown (i3wm restart) is detected 88 | * Bugfix: remove socket event source on ipc EOF status 89 | * Bugfix: proper error handling on internal ipc message sending 90 | 91 | Thanks to [sardemff7](https://github.com/sardemff7) for bug reports and feature requests. 92 | 93 | *Tony Crisci - March-10-2014* 94 | 95 | ## Version 0.0.1 96 | 97 | This initial release is a faithful and bindable representation of the ipc. The API should be considered stable enough to use in a new project. Please test thoroughly for memory issues before using it in production. 98 | 99 | *Tony Crisci - March-02-2014* 100 | -------------------------------------------------------------------------------- /run-tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import subprocess 4 | from subprocess import Popen 5 | import os 6 | from os import listdir, path 7 | from os.path import isfile, join 8 | import sys 9 | import re 10 | import time 11 | try: 12 | from shutil import which 13 | except ImportError: 14 | 15 | def which(cmd): 16 | path = os.getenv('PATH') 17 | for p in path.split(os.path.pathsep): 18 | p = os.path.join(p, cmd) 19 | if os.path.exists(p) and os.access(p, os.X_OK): 20 | return p 21 | 22 | 23 | if not hasattr(Popen, '__enter__'): 24 | 25 | def backported_enter(self): 26 | return self 27 | 28 | def backported_exit(self, type, value, traceback): 29 | if self.stdout: 30 | self.stdout.close() 31 | if self.stderr: 32 | self.stderr.close() 33 | try: # Flushing a BufferedWriter may raise an error 34 | if self.stdin: 35 | self.stdin.close() 36 | finally: 37 | # Wait for the process to terminate, to avoid zombies. 38 | return 39 | self.wait() 40 | 41 | Popen.__enter__ = backported_enter 42 | Popen.__exit__ = backported_exit 43 | 44 | PYTEST = 'pytest' 45 | XVFB = 'Xvfb' 46 | I3_BINARY = 'i3' 47 | MESON = 'meson' 48 | NINJA = 'ninja' 49 | SOCKETDIR = '/tmp/.X11-unix' 50 | FILEDIR = os.path.dirname(os.path.realpath(__file__)) 51 | BUILDDIR = os.path.join(FILEDIR, 'mesonbuild-test') 52 | 53 | 54 | def check_dependencies(): 55 | if not which(MESON): 56 | print('Meson is required to run tests') 57 | print('Command "%s" not found in PATH' % XVFB) 58 | sys.exit(127) 59 | 60 | if not which(NINJA): 61 | print('Ninja build is required to run tests') 62 | print('Command "%s" not found in PATH' % XVFB) 63 | sys.exit(127) 64 | 65 | if not which(XVFB): 66 | print('Xvfb is required to run tests') 67 | print('Command "%s" not found in PATH' % XVFB) 68 | sys.exit(127) 69 | 70 | if not which(I3_BINARY): 71 | print('i3 binary is required to run tests') 72 | print('Command "%s" not found in PATH' % I3_BINARY) 73 | sys.exit(127) 74 | 75 | if not which(PYTEST): 76 | print('pytest is required to run tests') 77 | print('Command %s not found in PATH' % PYTEST) 78 | sys.exit(127) 79 | 80 | 81 | def get_open_display(): 82 | if not os.path.isdir(SOCKETDIR): 83 | sys.stderr.write( 84 | 'warning: could not find the X11 socket directory at {}. Using display 0.\n' 85 | .format(SOCKETDIR)) 86 | sys.stderr.flush() 87 | return 0 88 | socket_re = re.compile(r'^X([0-9]+)$') 89 | socket_files = [f for f in listdir(SOCKETDIR) if socket_re.match(f)] 90 | displays = [int(socket_re.search(f).group(1)) for f in socket_files] 91 | open_display = min( 92 | [i for i in range(0, 93 | max(displays or [0]) + 2) if i not in displays]) 94 | return open_display 95 | 96 | 97 | def start_server(display): 98 | xvfb = Popen([XVFB, ':%d' % display]) 99 | # wait for the socket to make sure the server is running 100 | socketfile = path.join(SOCKETDIR, 'X%d' % display) 101 | tries = 0 102 | while True: 103 | if path.exists(socketfile): 104 | break 105 | else: 106 | tries += 1 107 | 108 | if tries > 100: 109 | print('could not start x server') 110 | xvfb.kill() 111 | sys.exit(1) 112 | 113 | time.sleep(0.1) 114 | 115 | return xvfb 116 | 117 | 118 | def run_pytest(display): 119 | env = os.environ.copy() 120 | env['DISPLAY'] = ':%d' % display 121 | env['_I3IPC_TEST'] = '1' 122 | env['GI_TYPELIB_PATH'] = os.path.join(BUILDDIR, 'i3ipc-glib') 123 | env['LD_LIBRARY_PATH'] = os.path.join(BUILDDIR, 'i3ipc-glib') 124 | return subprocess.call(['valgrind', PYTEST], env=env) 125 | 126 | 127 | def build_project(): 128 | ret = subprocess.call([MESON, BUILDDIR]) 129 | if ret != 0: 130 | return ret 131 | 132 | # TODO make incremental builds work 133 | ret = subprocess.call([NINJA, '-C', BUILDDIR, 'clean']) 134 | if ret != 0: 135 | return ret 136 | 137 | ret = subprocess.call([NINJA, '-C', BUILDDIR]) 138 | return ret 139 | 140 | 141 | def main(): 142 | check_dependencies() 143 | ret = build_project() 144 | if ret != 0: 145 | sys.exit(ret) 146 | display = get_open_display() 147 | 148 | with start_server(display) as server: 149 | ret = run_pytest(display) 150 | server.terminate() 151 | 152 | sys.exit(ret) 153 | 154 | 155 | if __name__ == '__main__': 156 | main() 157 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #ifndef __I3IPC_CONNECTION_H__ 22 | #define __I3IPC_CONNECTION_H__ 23 | 24 | #include 25 | 26 | #include "i3ipc-con.h" 27 | #include "i3ipc-event-types.h" 28 | #include "i3ipc-reply-types.h" 29 | 30 | #define I3IPC_MAGIC "i3-ipc" 31 | 32 | /** 33 | * SECTION: i3ipc-connection 34 | * @short_description: A connection to the i3 ipc to query i3 for the state of 35 | * containers and to subscribe to window manager events. 36 | * 37 | * Use this class to query information from the window manager about the state 38 | * of the workspaces, windows, etc. You can also subscribe to events such as 39 | * when certain window or workspace properties change. 40 | * 41 | */ 42 | 43 | #define I3IPC_TYPE_CONNECTION (i3ipc_connection_get_type()) 44 | #define I3IPC_CONNECTION(obj) \ 45 | (G_TYPE_CHECK_INSTANCE_CAST((obj), I3IPC_TYPE_CONNECTION, i3ipcConnection)) 46 | #define I3IPC_IS_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), I3IPC_TYPE_CONNECTION)) 47 | #define I3IPC_CONNECTION_CLASS(klass) \ 48 | (G_TYPE_CHECK_CLASS_CAST((klass), I3IPC_TYPE_CONNECTION, i3ipcConnectionClass)) 49 | #define I3IPC_IS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), I3IPC_TYPE_CONNECTION)) 50 | #define I3IPC_CONNECTION_GET_CLASS(obj) \ 51 | (G_TYPE_INSTANCE_GET_CLASS((obj), I3IPC_TYPE_CONNECTION, i3ipcConnectionClass)) 52 | 53 | typedef struct _i3ipcConnection i3ipcConnection; 54 | typedef struct _i3ipcConnectionClass i3ipcConnectionClass; 55 | typedef struct _i3ipcConnectionPrivate i3ipcConnectionPrivate; 56 | 57 | /** 58 | * i3ipcMessageType: 59 | * @I3IPC_MESSAGE_TYPE_COMMAND: 60 | * @I3IPC_MESSAGE_TYPE_GET_WORKSPACES: 61 | * @I3IPC_MESSAGE_TYPE_SUBSCRIBE: 62 | * @I3IPC_MESSAGE_TYPE_GET_OUTPUTS: 63 | * @I3IPC_MESSAGE_TYPE_GET_TREE: 64 | * @I3IPC_MESSAGE_TYPE_GET_MARKS: 65 | * @I3IPC_MESSAGE_TYPE_GET_BAR_CONFIG: 66 | * @I3IPC_MESSAGE_TYPE_GET_VERSION: 67 | * @I3IPC_MESSAGE_TYPE_GET_BINDING_MODES: 68 | * @I3IPC_MESSAGE_TYPE_GET_CONFIG: 69 | * 70 | * Message type enumeration for #i3ipcConnection 71 | * 72 | * This enumeration can be extended at later date 73 | */ 74 | typedef enum { /*< underscore_name=i3ipc_message_type >*/ 75 | I3IPC_MESSAGE_TYPE_COMMAND, 76 | I3IPC_MESSAGE_TYPE_GET_WORKSPACES, 77 | I3IPC_MESSAGE_TYPE_SUBSCRIBE, 78 | I3IPC_MESSAGE_TYPE_GET_OUTPUTS, 79 | I3IPC_MESSAGE_TYPE_GET_TREE, 80 | I3IPC_MESSAGE_TYPE_GET_MARKS, 81 | I3IPC_MESSAGE_TYPE_GET_BAR_CONFIG, 82 | I3IPC_MESSAGE_TYPE_GET_VERSION, 83 | I3IPC_MESSAGE_TYPE_GET_BINDING_MODES, 84 | I3IPC_MESSAGE_TYPE_GET_CONFIG, 85 | } i3ipcMessageType; 86 | 87 | struct _i3ipcConnection { 88 | GObject parent_instance; 89 | 90 | i3ipcConnectionPrivate *priv; 91 | }; 92 | 93 | struct _i3ipcConnectionClass { 94 | GObjectClass parent_class; 95 | 96 | /* class members */ 97 | }; 98 | 99 | /* used by I3IPC_TYPE_CONNECTION */ 100 | GType i3ipc_connection_get_type(void); 101 | 102 | i3ipcConnection *i3ipc_connection_new(const gchar *socket_path, GError **err); 103 | 104 | /* Method definitions */ 105 | 106 | gchar *i3ipc_connection_message(i3ipcConnection *self, i3ipcMessageType message_type, 107 | const gchar *payload, GError **err); 108 | 109 | GSList *i3ipc_connection_command(i3ipcConnection *self, const gchar *command, GError **err); 110 | 111 | i3ipcCommandReply *i3ipc_connection_subscribe(i3ipcConnection *self, i3ipcEvent events, 112 | GError **err); 113 | 114 | i3ipcConnection *i3ipc_connection_on(i3ipcConnection *self, const gchar *event, GClosure *callback, 115 | GError **err); 116 | 117 | GSList *i3ipc_connection_get_workspaces(i3ipcConnection *self, GError **err); 118 | 119 | GSList *i3ipc_connection_get_outputs(i3ipcConnection *self, GError **err); 120 | 121 | i3ipcCon *i3ipc_connection_get_tree(i3ipcConnection *self, GError **err); 122 | 123 | GSList *i3ipc_connection_get_marks(i3ipcConnection *self, GError **err); 124 | 125 | GSList *i3ipc_connection_get_bar_config_list(i3ipcConnection *self, GError **err); 126 | 127 | i3ipcBarConfigReply *i3ipc_connection_get_bar_config(i3ipcConnection *self, const gchar *bar_id, 128 | GError **err); 129 | 130 | i3ipcVersionReply *i3ipc_connection_get_version(i3ipcConnection *self, GError **err); 131 | 132 | gchar *i3ipc_connection_get_config(i3ipcConnection *self, GError **err); 133 | 134 | void i3ipc_connection_main(i3ipcConnection *self); 135 | 136 | void i3ipc_connection_main_with_context(i3ipcConnection *self, GMainContext *context); 137 | 138 | void i3ipc_connection_main_quit(i3ipcConnection *self); 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-reply-types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #ifndef __I3IPC_REPLY_TYPES_H__ 22 | #define __I3IPC_REPLY_TYPES_H__ 23 | 24 | #include 25 | 26 | #include "i3ipc-con.h" 27 | 28 | #define I3IPC_TYPE_COMMAND_REPLY (i3ipc_command_reply_get_type()) 29 | #define I3IPC_TYPE_VERSION_REPLY (i3ipc_version_reply_get_type()) 30 | #define I3IPC_TYPE_BAR_CONFIG_REPLY (i3ipc_bar_config_reply_get_type()) 31 | #define I3IPC_TYPE_OUTPUT_REPLY (i3ipc_output_reply_get_type()) 32 | #define I3IPC_TYPE_WORKSPACE_REPLY (i3ipc_workspace_reply_get_type()) 33 | 34 | typedef struct _i3ipcCommandReply i3ipcCommandReply; 35 | typedef struct _i3ipcVersionReply i3ipcVersionReply; 36 | typedef struct _i3ipcBarConfigReply i3ipcBarConfigReply; 37 | typedef struct _i3ipcOutputReply i3ipcOutputReply; 38 | typedef struct _i3ipcWorkspaceReply i3ipcWorkspaceReply; 39 | 40 | /** 41 | * i3ipcReplyType: 42 | * @I3IPC_REPLY_TYPE_COMMAND: 43 | * @I3IPC_REPLY_TYPE_WORKSPACES: 44 | * @I3IPC_REPLY_TYPE_SUBSCRIBE: 45 | * @I3IPC_REPLY_TYPE_OUTPUTS: 46 | * @I3IPC_REPLY_TYPE_TREE: 47 | * @I3IPC_REPLY_TYPE_MARKS: 48 | * @I3IPC_REPLY_TYPE_BAR_CONFIG: 49 | * @I3IPC_REPLY_TYPE_VERSION: 50 | * 51 | * Reply type enumeration for #i3ipcConnection 52 | * 53 | * This enumeration can be extended at later date 54 | */ 55 | typedef enum { /*< underscore_name=i3ipc_reply_type >*/ 56 | I3IPC_REPLY_TYPE_COMMAND, 57 | I3IPC_REPLY_TYPE_WORKSPACES, 58 | I3IPC_REPLY_TYPE_SUBSCRIBE, 59 | I3IPC_REPLY_TYPE_OUTPUTS, 60 | I3IPC_REPLY_TYPE_TREE, 61 | I3IPC_REPLY_TYPE_MARKS, 62 | I3IPC_REPLY_TYPE_BAR_CONFIG, 63 | I3IPC_REPLY_TYPE_VERSION, 64 | } i3ipcReplyType; 65 | 66 | /** 67 | * i3ipcCommandReply: 68 | * @success: whether or not the command succeeded 69 | * @parse_error: whether or not this was a parse error 70 | * @error: An error message 71 | * 72 | * The #i3ipcCommandReply is the primary structure for accessing the reply of 73 | * an ipc command. 74 | */ 75 | struct _i3ipcCommandReply { 76 | gboolean success; 77 | gboolean parse_error; 78 | gchar *error; 79 | /* for the 'open' command used in tests */ 80 | gint _id; 81 | }; 82 | 83 | i3ipcCommandReply *i3ipc_command_reply_copy(i3ipcCommandReply *reply); 84 | void i3ipc_command_reply_free(i3ipcCommandReply *reply); 85 | GType i3ipc_command_reply_get_type(void); 86 | 87 | /** 88 | * i3ipcVersionReply: 89 | * @major: The major version of i3. 90 | * @minor: The minor version of i3. 91 | * @patch: The patch version of i3. 92 | * @human_readable: A human-readable version of i3. 93 | * 94 | * The #i3ipcVersionReply is the primary structure for accessing the reply of 95 | * an ipc version command. 96 | */ 97 | struct _i3ipcVersionReply { 98 | gint major; 99 | gint minor; 100 | gint patch; 101 | gchar *human_readable; 102 | }; 103 | 104 | i3ipcVersionReply *i3ipc_version_reply_copy(i3ipcVersionReply *version); 105 | void i3ipc_version_reply_free(i3ipcVersionReply *version); 106 | GType i3ipc_version_reply_get_type(void); 107 | 108 | /** 109 | * i3ipcBarConfigReply: 110 | * @id: 111 | * @mode: 112 | * @position: 113 | * @status_command: 114 | * @font: 115 | * @workspace_buttons: 116 | * @binding_mode_indicator: 117 | * @verbose: 118 | * @strip_workspace_numbers: 119 | * @colors: (element-type utf8 utf8): 120 | * 121 | * The #i3ipcBarConfigReply is the primary structure for accessing the reply of 122 | * an ipc bar config command. 123 | */ 124 | struct _i3ipcBarConfigReply { 125 | gchar *id; 126 | gchar *mode; 127 | gchar *position; 128 | gchar *status_command; 129 | gchar *font; 130 | gboolean workspace_buttons; 131 | gboolean binding_mode_indicator; 132 | gboolean verbose; 133 | gboolean strip_workspace_numbers; 134 | GHashTable *colors; 135 | }; 136 | 137 | i3ipcBarConfigReply *i3ipc_bar_config_reply_copy(i3ipcBarConfigReply *config); 138 | void i3ipc_bar_config_reply_free(i3ipcBarConfigReply *config); 139 | GType i3ipc_bar_config_reply_get_type(void); 140 | 141 | /** 142 | * i3ipcOutputReply: 143 | * @name: 144 | * @active: 145 | * @current_workspace: 146 | * @rect: 147 | * 148 | * The #i3ipcOutputReply is the primary structure for accessing the reply of an 149 | * ipc output command. 150 | */ 151 | struct _i3ipcOutputReply { 152 | gchar *name; 153 | gboolean active; 154 | gchar *current_workspace; 155 | i3ipcRect *rect; 156 | }; 157 | 158 | i3ipcOutputReply *i3ipc_output_reply_copy(i3ipcOutputReply *output); 159 | void i3ipc_output_reply_free(i3ipcOutputReply *output); 160 | GType i3ipc_output_reply_get_type(void); 161 | 162 | /** 163 | * i3ipcWorkspaceReply: 164 | * @num: 165 | * @name: 166 | * @visible: 167 | * @focused: 168 | * @urgent: 169 | * @output: 170 | * @rect: 171 | * 172 | * The #i3ipcWorkspaceReply is the primary structure for accessing the reply of 173 | * an ipc workspace command. 174 | */ 175 | struct _i3ipcWorkspaceReply { 176 | gint num; 177 | gchar *name; 178 | gboolean visible; 179 | gboolean focused; 180 | gboolean urgent; 181 | gchar *output; 182 | i3ipcRect *rect; 183 | }; 184 | 185 | i3ipcWorkspaceReply *i3ipc_workspace_reply_copy(i3ipcWorkspaceReply *workspace); 186 | void i3ipc_workspace_reply_free(i3ipcWorkspaceReply *workspace); 187 | GType i3ipc_workspace_reply_get_type(void); 188 | 189 | #endif /* __I3IPC_REPLY_TYPES_H__ */ 190 | -------------------------------------------------------------------------------- /test/i3.config: -------------------------------------------------------------------------------- 1 | # i3 config file (v4) 2 | # 3 | # Please see http://i3wm.org/docs/userguide.html for a complete reference! 4 | # 5 | # This config file uses keycodes (bindsym) and was written for the QWERTY 6 | # layout. 7 | # 8 | # To get a config file with the same key positions, but for your current 9 | # layout, use the i3-config-wizard 10 | # 11 | 12 | # Font for window titles. Will also be used by the bar unless a different font 13 | # is used in the bar {} block below. 14 | font pango:monospace 8 15 | 16 | # This font is widely installed, provides lots of unicode glyphs, right-to-left 17 | # text rendering and scalability on retina/hidpi displays (thanks to pango). 18 | #font pango:DejaVu Sans Mono 8 19 | 20 | # Before i3 v4.8, we used to recommend this one as the default: 21 | # font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 22 | # The font above is very space-efficient, that is, it looks good, sharp and 23 | # clear in small sizes. However, its unicode glyph coverage is limited, the old 24 | # X core fonts rendering does not support right-to-left and this being a bitmap 25 | # font, it doesn’t scale on retina/hidpi displays. 26 | 27 | # use these keys for focus, movement, and resize directions when reaching for 28 | # the arrows is not convenient 29 | set $up l 30 | set $down k 31 | set $left j 32 | set $right semicolon 33 | 34 | # use Mouse+Mod1 to drag floating windows to their wanted position 35 | floating_modifier Mod1 36 | 37 | # start a terminal 38 | bindsym Mod1+Return exec i3-sensible-terminal 39 | 40 | # kill focused window 41 | bindsym Mod1+Shift+q kill 42 | 43 | # start dmenu (a program launcher) 44 | bindsym Mod1+d exec dmenu_run 45 | # There also is the (new) i3-dmenu-desktop which only displays applications 46 | # shipping a .desktop file. It is a wrapper around dmenu, so you need that 47 | # installed. 48 | # bindsym Mod1+d exec --no-startup-id i3-dmenu-desktop 49 | 50 | # change focus 51 | bindsym Mod1+$left focus left 52 | bindsym Mod1+$down focus down 53 | bindsym Mod1+$up focus up 54 | bindsym Mod1+$right focus right 55 | 56 | # alternatively, you can use the cursor keys: 57 | bindsym Mod1+Left focus left 58 | bindsym Mod1+Down focus down 59 | bindsym Mod1+Up focus up 60 | bindsym Mod1+Right focus right 61 | 62 | # move focused window 63 | bindsym Mod1+Shift+$left move left 64 | bindsym Mod1+Shift+$down move down 65 | bindsym Mod1+Shift+$up move up 66 | bindsym Mod1+Shift+$right move right 67 | 68 | # alternatively, you can use the cursor keys: 69 | bindsym Mod1+Shift+Left move left 70 | bindsym Mod1+Shift+Down move down 71 | bindsym Mod1+Shift+Up move up 72 | bindsym Mod1+Shift+Right move right 73 | 74 | # split in horizontal orientation 75 | bindsym Mod1+h split h 76 | 77 | # split in vertical orientation 78 | bindsym Mod1+v split v 79 | 80 | # enter fullscreen mode for the focused container 81 | bindsym Mod1+f fullscreen toggle 82 | 83 | # change container layout (stacked, tabbed, toggle split) 84 | bindsym Mod1+s layout stacking 85 | bindsym Mod1+w layout tabbed 86 | bindsym Mod1+e layout toggle split 87 | 88 | # toggle tiling / floating 89 | bindsym Mod1+Shift+space floating toggle 90 | 91 | # change focus between tiling / floating windows 92 | bindsym Mod1+space focus mode_toggle 93 | 94 | # focus the parent container 95 | bindsym Mod1+a focus parent 96 | 97 | # focus the child container 98 | #bindsym Mod1+d focus child 99 | 100 | # move the currently focused window to the scratchpad 101 | bindsym Mod1+Shift+minus move scratchpad 102 | 103 | # Show the next scratchpad window or hide the focused scratchpad window. 104 | # If there are multiple scratchpad windows, this command cycles through them. 105 | bindsym Mod1+minus scratchpad show 106 | 107 | # switch to workspace 108 | bindsym Mod1+1 workspace 1 109 | bindsym Mod1+2 workspace 2 110 | bindsym Mod1+3 workspace 3 111 | bindsym Mod1+4 workspace 4 112 | bindsym Mod1+5 workspace 5 113 | bindsym Mod1+6 workspace 6 114 | bindsym Mod1+7 workspace 7 115 | bindsym Mod1+8 workspace 8 116 | bindsym Mod1+9 workspace 9 117 | bindsym Mod1+0 workspace 10 118 | 119 | # move focused container to workspace 120 | bindsym Mod1+Shift+1 move container to workspace 1 121 | bindsym Mod1+Shift+2 move container to workspace 2 122 | bindsym Mod1+Shift+3 move container to workspace 3 123 | bindsym Mod1+Shift+4 move container to workspace 4 124 | bindsym Mod1+Shift+5 move container to workspace 5 125 | bindsym Mod1+Shift+6 move container to workspace 6 126 | bindsym Mod1+Shift+7 move container to workspace 7 127 | bindsym Mod1+Shift+8 move container to workspace 8 128 | bindsym Mod1+Shift+9 move container to workspace 9 129 | bindsym Mod1+Shift+0 move container to workspace 10 130 | 131 | # reload the configuration file 132 | bindsym Mod1+Shift+c reload 133 | # restart i3 inplace (preserves your layout/session, can be used to upgrade i3) 134 | bindsym Mod1+Shift+r restart 135 | # exit i3 (logs you out of your X session) 136 | bindsym Mod1+Shift+e exec "i3-nagbar -t warning -m 'You pressed the exit shortcut. Do you really want to exit i3? This will end your X session.' -b 'Yes, exit i3' 'i3-msg exit'" 137 | 138 | # resize window (you can also use the mouse for that) 139 | mode "resize" { 140 | # These bindings trigger as soon as you enter the resize mode 141 | 142 | # Pressing left will shrink the window’s width. 143 | # Pressing right will grow the window’s width. 144 | # Pressing up will shrink the window’s height. 145 | # Pressing down will grow the window’s height. 146 | bindsym $left resize shrink width 10 px or 10 ppt 147 | bindsym $down resize grow height 10 px or 10 ppt 148 | bindsym $up resize shrink height 10 px or 10 ppt 149 | bindsym $right resize grow width 10 px or 10 ppt 150 | 151 | # same bindings, but for the arrow keys 152 | bindsym Left resize shrink width 10 px or 10 ppt 153 | bindsym Down resize grow height 10 px or 10 ppt 154 | bindsym Up resize shrink height 10 px or 10 ppt 155 | bindsym Right resize grow width 10 px or 10 ppt 156 | 157 | # back to normal: Enter or Escape 158 | bindsym Return mode "default" 159 | bindsym Escape mode "default" 160 | } 161 | 162 | bindsym Mod1+r mode "resize" 163 | 164 | # Start i3bar to display a workspace bar (plus the system information i3status 165 | # finds out, if available) 166 | bar { 167 | #status_command i3status 168 | } 169 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-event-types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #include 22 | 23 | #include "i3ipc-con.h" 24 | 25 | #ifndef __I3IPC_EVENT_TYPES_H__ 26 | #define __I3IPC_EVENT_TYPES_H__ 27 | 28 | #define I3IPC_TYPE_WORKSPACE_EVENT (i3ipc_workspace_event_get_type()) 29 | #define I3IPC_TYPE_GENERIC_EVENT (i3ipc_generic_event_get_type()) 30 | #define I3IPC_TYPE_WINDOW_EVENT (i3ipc_window_event_get_type()) 31 | #define I3IPC_TYPE_BARCONFIG_UPDATE_EVENT (i3ipc_barconfig_update_event_get_type()) 32 | #define I3IPC_TYPE_BINDING_INFO (i3ipc_binding_info_get_type()) 33 | #define I3IPC_TYPE_BINDING_EVENT (i3ipc_binding_event_get_type()) 34 | 35 | typedef struct _i3ipcWorkspaceEvent i3ipcWorkspaceEvent; 36 | typedef struct _i3ipcGenericEvent i3ipcGenericEvent; 37 | typedef struct _i3ipcWindowEvent i3ipcWindowEvent; 38 | typedef struct _i3ipcBarconfigUpdateEvent i3ipcBarconfigUpdateEvent; 39 | typedef struct _i3ipcBindingInfo i3ipcBindingInfo; 40 | typedef struct _i3ipcBindingEvent i3ipcBindingEvent; 41 | 42 | /** 43 | * i3ipcEvent: 44 | * @I3IPC_EVENT_WORKSPACE: 45 | * @I3IPC_EVENT_OUTPUT: 46 | * @I3IPC_EVENT_MODE: 47 | * @I3IPC_EVENT_WINDOW: 48 | * @I3IPC_EVENT_BARCONFIG_UPDATE: 49 | * @I3IPC_EVENT_BINDING: 50 | * 51 | * Event enumeration for #i3ipcConnection 52 | * 53 | * This enumeration can be extended at later date 54 | */ 55 | typedef enum { /*< underscore_name=i3ipc_event >*/ 56 | I3IPC_EVENT_WORKSPACE = (1 << 0), 57 | I3IPC_EVENT_OUTPUT = (1 << 1), 58 | I3IPC_EVENT_MODE = (1 << 2), 59 | I3IPC_EVENT_WINDOW = (1 << 3), 60 | I3IPC_EVENT_BARCONFIG_UPDATE = (1 << 4), 61 | I3IPC_EVENT_BINDING = (1 << 5), 62 | } i3ipcEvent; 63 | 64 | /** 65 | * i3ipcWorkspaceEvent: 66 | * @change: indicates the type of change ("focus", "init", "empty", "urgent") 67 | * @current: when the change is "focus", the currently focused workspace 68 | * @old: when the change is "focus", the previously focused workspace 69 | * 70 | * The #i3ipcWorkspaceEvent contains data about a workspace event. 71 | */ 72 | struct _i3ipcWorkspaceEvent { 73 | gchar *change; 74 | i3ipcCon *current; 75 | i3ipcCon *old; 76 | }; 77 | 78 | i3ipcWorkspaceEvent *i3ipc_workspace_event_copy(i3ipcWorkspaceEvent *event); 79 | void i3ipc_workspace_event_free(i3ipcWorkspaceEvent *event); 80 | GType i3ipc_workspace_event_get_type(void); 81 | 82 | /** 83 | * i3ipcGenericEvent: 84 | * @change: details about what changed 85 | * 86 | * A #i3ipcGenericEvent contains a description of what has changed. 87 | */ 88 | struct _i3ipcGenericEvent { 89 | gchar *change; 90 | }; 91 | 92 | i3ipcGenericEvent *i3ipc_generic_event_copy(i3ipcGenericEvent *event); 93 | void i3ipc_generic_event_free(i3ipcGenericEvent *event); 94 | GType i3ipc_generic_event_get_type(void); 95 | 96 | /** 97 | * i3ipcWindowEvent: 98 | * @change: details about what changed 99 | * @container: The window's parent container 100 | * 101 | * A #i3ipcWindowEvent contains data about a window event. 102 | */ 103 | struct _i3ipcWindowEvent { 104 | gchar *change; 105 | i3ipcCon *container; 106 | }; 107 | 108 | i3ipcWindowEvent *i3ipc_window_event_copy(i3ipcWindowEvent *event); 109 | void i3ipc_window_event_free(i3ipcWindowEvent *event); 110 | GType i3ipc_window_event_get_type(void); 111 | 112 | /** 113 | * i3ipcBarconfigUpdateEvent: 114 | * @id: specifies which bar instance the sent config update belongs 115 | * @hidden_state: indicates the hidden_state of the i3bar instance 116 | * @mode: corresponds to the current mode 117 | * 118 | * An #i3ipcBarconfigUpdateEvent reports options from the barconfig of the 119 | * specified bar_id that were updated in i3. 120 | */ 121 | struct _i3ipcBarconfigUpdateEvent { 122 | gchar *id; 123 | gchar *hidden_state; 124 | gchar *mode; 125 | }; 126 | 127 | i3ipcBarconfigUpdateEvent *i3ipc_barconfig_update_event_copy(i3ipcBarconfigUpdateEvent *event); 128 | void i3ipc_barconfig_update_event_free(i3ipcBarconfigUpdateEvent *event); 129 | GType i3ipc_barconfig_update_event_get_type(void); 130 | 131 | /** 132 | * i3ipcBindingInfo: 133 | * @command: The i3 command that is configured to run for this binding. 134 | * @mods: (element-type utf8): The modifier keys that were configured with this binding. 135 | * @input_code: If the binding was configured with bindcode, this will be the 136 | * key code that was given for the binding. If the binding is a mouse binding, 137 | * it will be the number of the mouse button that was pressed. Otherwise it 138 | * will be 0. 139 | * @symbol: If this is a keyboard binding that was configured with bindsym, 140 | * this field will contain the given symbol. 141 | * @input_type: This will be "keyboard" or "mouse" depending on whether or not 142 | * this was a keyboard or a mouse binding. 143 | */ 144 | struct _i3ipcBindingInfo { 145 | gchar *command; 146 | GSList *mods; 147 | gint input_code; 148 | gchar *symbol; 149 | gchar *input_type; 150 | }; 151 | 152 | i3ipcBindingInfo *i3ipc_binding_info_copy(i3ipcBindingInfo *info); 153 | void i3ipc_binding_info_free(i3ipcBindingInfo *info); 154 | GType i3ipc_binding_info_get_type(void); 155 | 156 | /** 157 | * i3ipcBindingEvent: 158 | * @binding: A #i3ipcBindingInfo that contains info about this binding 159 | * @change: The type of binding event that was triggered (right now, only "run"). 160 | */ 161 | struct _i3ipcBindingEvent { 162 | i3ipcBindingInfo *binding; 163 | gchar *change; 164 | }; 165 | 166 | i3ipcBindingEvent *i3ipc_binding_event_copy(i3ipcBindingEvent *event); 167 | void i3ipc_binding_event_free(i3ipcBindingEvent *event); 168 | GType i3ipc_binding_event_get_type(void); 169 | 170 | #endif /* __I3IPC_EVENT_TYPES_H__ */ 171 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-reply-types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #include "i3ipc-reply-types.h" 22 | 23 | #include 24 | 25 | #include "i3ipc-con.h" 26 | 27 | /** 28 | * i3ipc_command_reply_copy: 29 | * @reply: a #i3ipcCommandReply struct 30 | * 31 | * Creates a dynamically allocated i3ipc command reply as a copy of @reply. 32 | * 33 | * Returns: (transfer full): a newly-allocated copy of @reply 34 | */ 35 | i3ipcCommandReply *i3ipc_command_reply_copy(i3ipcCommandReply *reply) { 36 | i3ipcCommandReply *retval; 37 | 38 | g_return_val_if_fail(reply != NULL, NULL); 39 | 40 | retval = g_slice_new0(i3ipcCommandReply); 41 | *retval = *reply; 42 | 43 | retval->error = g_strdup(reply->error); 44 | 45 | return retval; 46 | } 47 | 48 | /** 49 | * i3ipc_command_reply_free: 50 | * @reply: (allow-none): a #i3ipcCommandReply 51 | * 52 | * Frees @reply. If @reply is %NULL, it simply returns. 53 | */ 54 | void i3ipc_command_reply_free(i3ipcCommandReply *reply) { 55 | if (!reply) { 56 | return; 57 | } 58 | 59 | g_free(reply->error); 60 | 61 | g_slice_free(i3ipcCommandReply, reply); 62 | } 63 | 64 | G_DEFINE_BOXED_TYPE(i3ipcCommandReply, i3ipc_command_reply, i3ipc_command_reply_copy, 65 | i3ipc_command_reply_free); 66 | 67 | /** 68 | * i3ipc_version_reply_copy: 69 | * @version: a #i3ipcVersionReply struct 70 | * 71 | * Creates a dynamically allocated i3ipc version reply as a copy of @version. 72 | * 73 | * Returns: (transfer full): a newly-allocated copy of @version 74 | */ 75 | i3ipcVersionReply *i3ipc_version_reply_copy(i3ipcVersionReply *version) { 76 | i3ipcVersionReply *retval; 77 | 78 | g_return_val_if_fail(version != NULL, NULL); 79 | 80 | retval = g_slice_new0(i3ipcVersionReply); 81 | *retval = *version; 82 | 83 | retval->human_readable = g_strdup(version->human_readable); 84 | 85 | return retval; 86 | } 87 | 88 | /** 89 | * i3ipc_version_reply_free: 90 | * @version: (allow-none): a #i3ipcVersionReply 91 | * 92 | * Frees @version. If @version is %NULL, it simply returns. 93 | */ 94 | void i3ipc_version_reply_free(i3ipcVersionReply *version) { 95 | if (!version) { 96 | return; 97 | } 98 | 99 | g_free(version->human_readable); 100 | g_slice_free(i3ipcVersionReply, version); 101 | } 102 | 103 | G_DEFINE_BOXED_TYPE(i3ipcVersionReply, i3ipc_version_reply, i3ipc_version_reply_copy, 104 | i3ipc_version_reply_free); 105 | 106 | static void bar_config_colors_copy_func(gpointer _key, gpointer _value, gpointer user_data) { 107 | gchar *key = _key; 108 | gchar *value = _value; 109 | GHashTable *copy = user_data; 110 | 111 | g_hash_table_insert(copy, g_strdup(key), g_strdup(value)); 112 | } 113 | 114 | /** 115 | * i3ipc_bar_config_reply_copy: 116 | * @config: a #i3ipcBarConfigReply struct 117 | * 118 | * Creates a dynamically allocated i3ipc version reply as a copy of @config. 119 | * 120 | * Returns: (transfer full): a newly-allocated copy of @config 121 | */ 122 | i3ipcBarConfigReply *i3ipc_bar_config_reply_copy(i3ipcBarConfigReply *config) { 123 | i3ipcBarConfigReply *retval; 124 | 125 | g_return_val_if_fail(config != NULL, NULL); 126 | 127 | retval = g_slice_new0(i3ipcBarConfigReply); 128 | *retval = *config; 129 | 130 | retval->position = g_strdup(config->position); 131 | retval->font = g_strdup(config->font); 132 | retval->mode = g_strdup(config->mode); 133 | retval->id = g_strdup(config->id); 134 | retval->status_command = g_strdup(config->status_command); 135 | 136 | retval->colors = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); 137 | g_hash_table_foreach(config->colors, bar_config_colors_copy_func, retval->colors); 138 | 139 | return retval; 140 | } 141 | 142 | /** 143 | * i3ipc_bar_config_reply_free: 144 | * @config: (allow-none): a #i3ipcBarConfigReply 145 | * 146 | * Frees @config. If @config is %NULL, it simply returns. 147 | */ 148 | void i3ipc_bar_config_reply_free(i3ipcBarConfigReply *config) { 149 | if (!config) { 150 | return; 151 | } 152 | 153 | g_free(config->id); 154 | g_free(config->mode); 155 | g_free(config->position); 156 | g_free(config->status_command); 157 | g_free(config->font); 158 | g_hash_table_destroy(config->colors); 159 | 160 | g_slice_free(i3ipcBarConfigReply, config); 161 | } 162 | 163 | G_DEFINE_BOXED_TYPE(i3ipcBarConfigReply, i3ipc_bar_config_reply, i3ipc_bar_config_reply_copy, 164 | i3ipc_bar_config_reply_free); 165 | 166 | /** 167 | * i3ipc_output_reply_copy: 168 | * @output: a #i3ipcOutputReply struct 169 | * 170 | * Creates a dynamically allocated i3ipc output reply as a copy of @output. 171 | * 172 | * Returns: (transfer full): a newly-allocated copy of @output 173 | */ 174 | i3ipcOutputReply *i3ipc_output_reply_copy(i3ipcOutputReply *output) { 175 | i3ipcOutputReply *retval; 176 | 177 | g_return_val_if_fail(output != NULL, NULL); 178 | 179 | retval = g_slice_new0(i3ipcOutputReply); 180 | *retval = *output; 181 | 182 | retval->name = g_strdup(output->name); 183 | retval->current_workspace = g_strdup(output->current_workspace); 184 | retval->rect = i3ipc_rect_copy(output->rect); 185 | 186 | return retval; 187 | } 188 | 189 | /** 190 | * i3ipc_output_reply_free: 191 | * @output: (allow-none): a #i3ipcOutputReply 192 | * 193 | * Frees @output. If @output is %NULL, it simply returns. 194 | */ 195 | void i3ipc_output_reply_free(i3ipcOutputReply *output) { 196 | if (!output) { 197 | return; 198 | } 199 | 200 | g_free(output->name); 201 | g_free(output->current_workspace); 202 | i3ipc_rect_free(output->rect); 203 | 204 | g_slice_free(i3ipcOutputReply, output); 205 | } 206 | 207 | G_DEFINE_BOXED_TYPE(i3ipcOutputReply, i3ipc_output_reply, i3ipc_output_reply_copy, 208 | i3ipc_output_reply_free); 209 | 210 | /** 211 | * i3ipc_workspace_reply_copy: 212 | * @workspace: a #i3ipcWorkspaceReply 213 | * 214 | * Creates a dynamically allocated i3ipc workspace reply as a copy of 215 | * @workspace. 216 | * 217 | * Returns: (transfer full): a newly-allocated copy of @workspace 218 | */ 219 | i3ipcWorkspaceReply *i3ipc_workspace_reply_copy(i3ipcWorkspaceReply *workspace) { 220 | i3ipcWorkspaceReply *retval; 221 | 222 | g_return_val_if_fail(workspace != NULL, NULL); 223 | 224 | retval = g_slice_new0(i3ipcWorkspaceReply); 225 | *retval = *workspace; 226 | 227 | retval->name = g_strdup(workspace->name); 228 | retval->output = g_strdup(workspace->output); 229 | retval->rect = i3ipc_rect_copy(workspace->rect); 230 | 231 | return retval; 232 | } 233 | 234 | /** 235 | * i3ipc_workspace_reply_free: 236 | * @workspace: (allow-none): a #i3ipcWorkspaceReply 237 | * 238 | * Frees @workspace. If @workspace is %NULL, it simply returns. 239 | */ 240 | void i3ipc_workspace_reply_free(i3ipcWorkspaceReply *workspace) { 241 | if (!workspace) { 242 | return; 243 | } 244 | 245 | g_free(workspace->name); 246 | g_free(workspace->output); 247 | i3ipc_rect_free(workspace->rect); 248 | 249 | g_slice_free(i3ipcWorkspaceReply, workspace); 250 | } 251 | 252 | G_DEFINE_BOXED_TYPE(i3ipcWorkspaceReply, i3ipc_workspace_reply, i3ipc_workspace_reply_copy, 253 | i3ipc_workspace_reply_free); 254 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This package was debianized by Alexandre ACEBEDO on 2 | Sun, 04 August 2015 09:23:23 +0200. 3 | 4 | Copyright (C) 2015 Alexandre ACEBEDO 5 | Alexandre ACEBEDO 6 | 7 | License: 8 | GNU LESSER GENERAL PUBLIC LICENSE 9 | Version 3, 29 June 2007 10 | 11 | Copyright (C) 2007 Free Software Foundation, Inc. 12 | Everyone is permitted to copy and distribute verbatim copies 13 | of this license document, but changing it is not allowed. 14 | 15 | 16 | This version of the GNU Lesser General Public License incorporates 17 | the terms and conditions of version 3 of the GNU General Public 18 | License, supplemented by the additional permissions listed below. 19 | 20 | 0. Additional Definitions. 21 | 22 | As used herein, "this License" refers to version 3 of the GNU Lesser 23 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 24 | General Public License. 25 | 26 | "The Library" refers to a covered work governed by this License, 27 | other than an Application or a Combined Work as defined below. 28 | 29 | An "Application" is any work that makes use of an interface provided 30 | by the Library, but which is not otherwise based on the Library. 31 | Defining a subclass of a class defined by the Library is deemed a mode 32 | of using an interface provided by the Library. 33 | 34 | A "Combined Work" is a work produced by combining or linking an 35 | Application with the Library. The particular version of the Library 36 | with which the Combined Work was made is also called the "Linked 37 | Version". 38 | 39 | The "Minimal Corresponding Source" for a Combined Work means the 40 | Corresponding Source for the Combined Work, excluding any source code 41 | for portions of the Combined Work that, considered in isolation, are 42 | based on the Application, and not on the Linked Version. 43 | 44 | The "Corresponding Application Code" for a Combined Work means the 45 | object code and/or source code for the Application, including any data 46 | and utility programs needed for reproducing the Combined Work from the 47 | Application, but excluding the System Libraries of the Combined Work. 48 | 49 | 1. Exception to Section 3 of the GNU GPL. 50 | 51 | You may convey a covered work under sections 3 and 4 of this License 52 | without being bound by section 3 of the GNU GPL. 53 | 54 | 2. Conveying Modified Versions. 55 | 56 | If you modify a copy of the Library, and, in your modifications, a 57 | facility refers to a function or data to be supplied by an Application 58 | that uses the facility (other than as an argument passed when the 59 | facility is invoked), then you may convey a copy of the modified 60 | version: 61 | 62 | a) under this License, provided that you make a good faith effort to 63 | ensure that, in the event an Application does not supply the 64 | function or data, the facility still operates, and performs 65 | whatever part of its purpose remains meaningful, or 66 | 67 | b) under the GNU GPL, with none of the additional permissions of 68 | this License applicable to that copy. 69 | 70 | 3. Object Code Incorporating Material from Library Header Files. 71 | 72 | The object code form of an Application may incorporate material from 73 | a header file that is part of the Library. You may convey such object 74 | code under terms of your choice, provided that, if the incorporated 75 | material is not limited to numerical parameters, data structure 76 | layouts and accessors, or small macros, inline functions and templates 77 | (ten or fewer lines in length), you do both of the following: 78 | 79 | a) Give prominent notice with each copy of the object code that the 80 | Library is used in it and that the Library and its use are 81 | covered by this License. 82 | 83 | b) Accompany the object code with a copy of the GNU GPL and this license 84 | document. 85 | 86 | 4. Combined Works. 87 | 88 | You may convey a Combined Work under terms of your choice that, 89 | taken together, effectively do not restrict modification of the 90 | portions of the Library contained in the Combined Work and reverse 91 | engineering for debugging such modifications, if you also do each of 92 | the following: 93 | 94 | a) Give prominent notice with each copy of the Combined Work that 95 | the Library is used in it and that the Library and its use are 96 | covered by this License. 97 | 98 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 99 | document. 100 | 101 | c) For a Combined Work that displays copyright notices during 102 | execution, include the copyright notice for the Library among 103 | these notices, as well as a reference directing the user to the 104 | copies of the GNU GPL and this license document. 105 | 106 | d) Do one of the following: 107 | 108 | 0) Convey the Minimal Corresponding Source under the terms of this 109 | License, and the Corresponding Application Code in a form 110 | suitable for, and under terms that permit, the user to 111 | recombine or relink the Application with a modified version of 112 | the Linked Version to produce a modified Combined Work, in the 113 | manner specified by section 6 of the GNU GPL for conveying 114 | Corresponding Source. 115 | 116 | 1) Use a suitable shared library mechanism for linking with the 117 | Library. A suitable mechanism is one that (a) uses at run time 118 | a copy of the Library already present on the user's computer 119 | system, and (b) will operate properly with a modified version 120 | of the Library that is interface-compatible with the Linked 121 | Version. 122 | 123 | e) Provide Installation Information, but only if you would otherwise 124 | be required to provide such information under section 6 of the 125 | GNU GPL, and only to the extent that such information is 126 | necessary to install and execute a modified version of the 127 | Combined Work produced by recombining or relinking the 128 | Application with a modified version of the Linked Version. (If 129 | you use option 4d0, the Installation Information must accompany 130 | the Minimal Corresponding Source and Corresponding Application 131 | Code. If you use option 4d1, you must provide the Installation 132 | Information in the manner specified by section 6 of the GNU GPL 133 | for conveying Corresponding Source.) 134 | 135 | 5. Combined Libraries. 136 | 137 | You may place library facilities that are a work based on the 138 | Library side by side in a single library together with other library 139 | facilities that are not Applications and are not covered by this 140 | License, and convey such a combined library under terms of your 141 | choice, if you do both of the following: 142 | 143 | a) Accompany the combined library with a copy of the same work based 144 | on the Library, uncombined with any other library facilities, 145 | conveyed under the terms of this License. 146 | 147 | b) Give prominent notice with the combined library that part of it 148 | is a work based on the Library, and explaining where to find the 149 | accompanying uncombined form of the same work. 150 | 151 | 6. Revised Versions of the GNU Lesser General Public License. 152 | 153 | The Free Software Foundation may publish revised and/or new versions 154 | of the GNU Lesser General Public License from time to time. Such new 155 | versions will be similar in spirit to the present version, but may 156 | differ in detail to address new problems or concerns. 157 | 158 | Each version is given a distinguishing version number. If the 159 | Library as you received it specifies that a certain numbered version 160 | of the GNU Lesser General Public License "or any later version" 161 | applies to it, you have the option of following the terms and 162 | conditions either of that published version or of any later version 163 | published by the Free Software Foundation. If the Library as you 164 | received it does not specify a version number of the GNU Lesser 165 | General Public License, you may choose any version of the GNU Lesser 166 | General Public License ever published by the Free Software Foundation. 167 | 168 | If the Library as you received it specifies that a proxy can decide 169 | whether future versions of the GNU Lesser General Public License shall 170 | apply, that proxy's public statement of acceptance of any version is 171 | permanent authorization for you to choose that version for the 172 | Library. 173 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-event-types.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | */ 19 | 20 | #include "i3ipc-event-types.h" 21 | 22 | #include 23 | 24 | #include "i3ipc-con.h" 25 | #include "i3ipc-enum-types.h" 26 | 27 | /** 28 | * i3ipc_workspace_event_copy: 29 | * @event: a #i3ipcWorkspaceEvent 30 | * 31 | * Creates a dynamically allocated i3ipc workspace event data container as a copy 32 | * of @event. 33 | * 34 | * Returns: (transfer full): a newly-allocated copy of @event 35 | */ 36 | i3ipcWorkspaceEvent *i3ipc_workspace_event_copy(i3ipcWorkspaceEvent *event) { 37 | i3ipcWorkspaceEvent *retval; 38 | 39 | g_return_val_if_fail(event != NULL, NULL); 40 | 41 | retval = g_slice_new0(i3ipcWorkspaceEvent); 42 | *retval = *event; 43 | 44 | retval->change = g_strdup(event->change); 45 | 46 | if (event->current && I3IPC_IS_CON(event->current)) { 47 | g_object_ref(event->current); 48 | } 49 | 50 | if (event->old && I3IPC_IS_CON(event->old)) { 51 | g_object_ref(event->old); 52 | } 53 | 54 | return retval; 55 | } 56 | 57 | /** 58 | * i3ipc_workspace_event_free: 59 | * @event: (allow-none): a #i3ipcWorkspaceEvent 60 | * 61 | * Frees @event. If @event is %NULL, it simply returns. 62 | */ 63 | void i3ipc_workspace_event_free(i3ipcWorkspaceEvent *event) { 64 | if (!event) { 65 | return; 66 | } 67 | 68 | g_free(event->change); 69 | 70 | if (event->current && I3IPC_IS_CON(event->current)) { 71 | g_clear_object(&event->current); 72 | } 73 | 74 | if (event->old && I3IPC_IS_CON(event->old)) { 75 | g_clear_object(&event->old); 76 | } 77 | 78 | g_slice_free(i3ipcWorkspaceEvent, event); 79 | } 80 | 81 | G_DEFINE_BOXED_TYPE(i3ipcWorkspaceEvent, i3ipc_workspace_event, i3ipc_workspace_event_copy, 82 | i3ipc_workspace_event_free); 83 | 84 | /** 85 | * i3ipc_generic_event_copy: 86 | * @event: a #i3ipcGenericEvent 87 | * 88 | * Creates a dynamically allocated i3ipc generic event data container as a copy 89 | * of @event. 90 | * 91 | * Returns: (transfer full): a newly-allocated copy of @event 92 | */ 93 | i3ipcGenericEvent *i3ipc_generic_event_copy(i3ipcGenericEvent *event) { 94 | i3ipcGenericEvent *retval; 95 | 96 | g_return_val_if_fail(event != NULL, NULL); 97 | 98 | retval = g_slice_new0(i3ipcGenericEvent); 99 | *retval = *event; 100 | 101 | retval->change = g_strdup(event->change); 102 | 103 | return retval; 104 | } 105 | 106 | /** 107 | * i3ipc_generic_event_free: 108 | * @event: (allow-none): a #i3ipcGenericEvent 109 | * 110 | * Frees @event. If @event is %NULL, it simply returns. 111 | */ 112 | void i3ipc_generic_event_free(i3ipcGenericEvent *event) { 113 | if (!event) { 114 | return; 115 | } 116 | 117 | g_free(event->change); 118 | 119 | g_slice_free(i3ipcGenericEvent, event); 120 | } 121 | 122 | G_DEFINE_BOXED_TYPE(i3ipcGenericEvent, i3ipc_generic_event, i3ipc_generic_event_copy, 123 | i3ipc_generic_event_free); 124 | 125 | /** 126 | * i3ipc_window_event_copy: 127 | * @event: a #i3ipcWindowEvent 128 | * 129 | * Creates a dynamically allocated i3ipc window event data container as a copy 130 | * of @event. 131 | * 132 | * Returns: (transfer full): a newly-allocated copy of @event 133 | */ 134 | i3ipcWindowEvent *i3ipc_window_event_copy(i3ipcWindowEvent *event) { 135 | i3ipcWindowEvent *retval; 136 | 137 | g_return_val_if_fail(event != NULL, NULL); 138 | 139 | retval = g_slice_new0(i3ipcWindowEvent); 140 | *retval = *event; 141 | 142 | retval->change = g_strdup(event->change); 143 | g_object_ref(event->container); 144 | 145 | return retval; 146 | } 147 | 148 | /** 149 | * i3ipc_window_event_free: 150 | * @event: (allow-none): a #i3ipcWindowEvent 151 | * 152 | * Frees @event. If @event is %NULL, it simply returns. 153 | */ 154 | void i3ipc_window_event_free(i3ipcWindowEvent *event) { 155 | if (!event) { 156 | return; 157 | } 158 | 159 | g_free(event->change); 160 | 161 | g_clear_object(&event->container); 162 | 163 | g_slice_free(i3ipcWindowEvent, event); 164 | } 165 | 166 | G_DEFINE_BOXED_TYPE(i3ipcWindowEvent, i3ipc_window_event, i3ipc_window_event_copy, 167 | i3ipc_window_event_free); 168 | 169 | /** 170 | * i3ipc_barconfig_update_event_copy: 171 | * @event: a #i3ipcBarconfigUpdateEvent 172 | * 173 | * Creates a dynamically allocated i3ipc barconfig update event data container 174 | * as a copy of @event. 175 | * Returns: (transfer full): a newly-allocated copy of @event 176 | */ 177 | i3ipcBarconfigUpdateEvent *i3ipc_barconfig_update_event_copy(i3ipcBarconfigUpdateEvent *event) { 178 | i3ipcBarconfigUpdateEvent *retval; 179 | 180 | g_return_val_if_fail(event != NULL, NULL); 181 | 182 | retval = g_slice_new0(i3ipcBarconfigUpdateEvent); 183 | *retval = *event; 184 | 185 | retval->hidden_state = g_strdup(event->hidden_state); 186 | retval->id = g_strdup(event->id); 187 | retval->mode = g_strdup(event->mode); 188 | 189 | return retval; 190 | } 191 | 192 | /** 193 | * i3ipc_barconfig_update_free: 194 | * @event: (allow-none): a #i3ipcBarconfigUpdateEvent 195 | * 196 | * Frees @event. If @event is %NULL, it simply returns. 197 | */ 198 | void i3ipc_barconfig_update_event_free(i3ipcBarconfigUpdateEvent *event) { 199 | if (!event) { 200 | return; 201 | } 202 | 203 | g_free(event->id); 204 | g_free(event->hidden_state); 205 | g_free(event->mode); 206 | 207 | g_slice_free(i3ipcBarconfigUpdateEvent, event); 208 | } 209 | 210 | G_DEFINE_BOXED_TYPE(i3ipcBarconfigUpdateEvent, i3ipc_barconfig_update_event, 211 | i3ipc_barconfig_update_event_copy, i3ipc_barconfig_update_event_free); 212 | 213 | /** 214 | * i3ipc_binding_info_copy: 215 | * @info: a #i3ipcBindingInfo 216 | * 217 | * Creates a dynamically allocated i3ipc binding info container as a copy of 218 | * @info. 219 | * Returns: (transfer full): a newly-allocated copy of @info 220 | */ 221 | i3ipcBindingInfo *i3ipc_binding_info_copy(i3ipcBindingInfo *info) { 222 | i3ipcBindingInfo *retval; 223 | 224 | g_return_val_if_fail(info != NULL, NULL); 225 | 226 | retval = g_slice_new0(i3ipcBindingInfo); 227 | *retval = *info; 228 | 229 | retval->command = g_strdup(info->command); 230 | retval->symbol = g_strdup(info->symbol); 231 | retval->input_type = g_strdup(info->input_type); 232 | retval->mods = g_slist_copy_deep(info->mods, (GCopyFunc)g_strdup, NULL); 233 | 234 | return retval; 235 | } 236 | 237 | /** 238 | * i3ipc_binding_info_free: 239 | * @info: (allow-none): a #i3ipcBindingInfo 240 | * 241 | * Frees @info. If @info is %NULL, it simply returns. 242 | */ 243 | void i3ipc_binding_info_free(i3ipcBindingInfo *info) { 244 | if (!info) { 245 | return; 246 | } 247 | 248 | g_free(info->command); 249 | g_free(info->input_type); 250 | g_free(info->symbol); 251 | g_slist_free_full(info->mods, g_free); 252 | 253 | g_slice_free(i3ipcBindingInfo, info); 254 | } 255 | 256 | G_DEFINE_BOXED_TYPE(i3ipcBindingInfo, i3ipc_binding_info, i3ipc_binding_info_copy, 257 | i3ipc_binding_info_free); 258 | 259 | /** 260 | * i3ipc_binding_event_copy: 261 | * @event: a #i3ipcBindingEvent 262 | * 263 | * Creates a dynamically allocated i3ipc binding event data container as a copy 264 | * of @event. 265 | * Returns: (transfer full): a newly-allocated copy of @event 266 | */ 267 | i3ipcBindingEvent *i3ipc_binding_event_copy(i3ipcBindingEvent *event) { 268 | i3ipcBindingEvent *retval; 269 | 270 | g_return_val_if_fail(event != NULL, NULL); 271 | 272 | retval = g_slice_new0(i3ipcBindingEvent); 273 | *retval = *event; 274 | 275 | retval->binding = i3ipc_binding_info_copy(event->binding); 276 | retval->change = g_strdup(event->change); 277 | 278 | return retval; 279 | } 280 | 281 | /** 282 | * i3ipc_binding_event_free: 283 | * @event: (allow-none): a #i3ipcBindingEvent 284 | * 285 | * Frees @event. If @event is %NULL, it simply returns. 286 | */ 287 | void i3ipc_binding_event_free(i3ipcBindingEvent *event) { 288 | if (!event) { 289 | return; 290 | } 291 | 292 | g_free(event->change); 293 | i3ipc_binding_info_free(event->binding); 294 | 295 | g_slice_free(i3ipcBindingEvent, event); 296 | } 297 | 298 | G_DEFINE_BOXED_TYPE(i3ipcBindingEvent, i3ipc_binding_event, i3ipc_binding_event_copy, 299 | i3ipc_binding_event_free); 300 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /i3ipc-glib/i3ipc-con.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of i3-ipc. 3 | * 4 | * i3-ipc is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * i3-ipc is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with i3-ipc. If not, see . 16 | * 17 | * Copyright © 2014, Tony Crisci 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include "i3ipc-con-private.h" 25 | #include "i3ipc-connection.h" 26 | 27 | /** 28 | * i3ipc_rect_copy: 29 | * @rect: an #i3ipcRect struct 30 | * 31 | * Creates a dynamically allocated i3ipc rect as a copy of @rect. 32 | * 33 | * Returns: (transfer full): a newly-allocated copy of @rect. 34 | */ 35 | i3ipcRect *i3ipc_rect_copy(i3ipcRect *rect) { 36 | i3ipcRect *retval; 37 | 38 | g_return_val_if_fail(rect != NULL, NULL); 39 | 40 | retval = g_slice_new0(i3ipcRect); 41 | *retval = *rect; 42 | 43 | return retval; 44 | } 45 | 46 | /** 47 | * i3ipc_rect_free: 48 | * @rect: (allow-none): an #i3ipcRect 49 | * 50 | * Frees @rect. If @rect is %NULL, it simply returns. 51 | */ 52 | void i3ipc_rect_free(i3ipcRect *rect) { 53 | if (!rect) { 54 | return; 55 | } 56 | 57 | g_slice_free(i3ipcRect, rect); 58 | } 59 | 60 | G_DEFINE_BOXED_TYPE(i3ipcRect, i3ipc_rect, i3ipc_rect_copy, i3ipc_rect_free); 61 | 62 | struct _i3ipcConPrivate { 63 | gulong id; 64 | gchar *name; 65 | gchar *border; 66 | gint current_border_width; 67 | gchar *layout; 68 | gchar *orientation; 69 | gfloat percent; 70 | guint window; 71 | gboolean urgent; 72 | gboolean focused; 73 | gboolean fullscreen_mode; 74 | gchar *type; 75 | gchar *window_class; 76 | gchar *window_role; 77 | gchar *window_instance; 78 | gchar *mark; 79 | 80 | i3ipcConnection *conn; 81 | i3ipcRect *rect; 82 | i3ipcRect *deco_rect; 83 | GList *nodes; 84 | GList *floating_nodes; 85 | GList *focus; 86 | i3ipcCon *parent; 87 | }; 88 | 89 | G_DEFINE_TYPE_WITH_PRIVATE(i3ipcCon, i3ipc_con, G_TYPE_OBJECT); 90 | 91 | enum { 92 | PROP_0, 93 | 94 | PROP_ID, 95 | PROP_NAME, 96 | PROP_BORDER, 97 | PROP_CURRENT_BORDER_WIDTH, 98 | PROP_LAYOUT, 99 | PROP_ORIENTATION, 100 | PROP_PERCENT, 101 | PROP_WINDOW, 102 | PROP_URGENT, 103 | PROP_FOCUSED, 104 | PROP_FULLSCREEN_MODE, 105 | PROP_TYPE, 106 | PROP_WINDOW_CLASS, 107 | PROP_WINDOW_ROLE, 108 | PROP_WINDOW_INSTANCE, 109 | PROP_MARK, 110 | 111 | PROP_RECT, 112 | PROP_DECO_RECT, 113 | PROP_PARENT, 114 | PROP_NODES, 115 | PROP_FLOATING_NODES, 116 | PROP_FOCUS, 117 | 118 | N_PROPERTIES 119 | }; 120 | 121 | static GParamSpec *obj_properties[N_PROPERTIES] = { 122 | NULL, 123 | }; 124 | 125 | static void i3ipc_con_set_property(GObject *object, guint property_id, const GValue *value, 126 | GParamSpec *pspec) { 127 | // i3ipcCon *self = I3IPC_CON(object); 128 | 129 | switch (property_id) { 130 | default: 131 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 132 | } 133 | } 134 | 135 | static void i3ipc_con_get_property(GObject *object, guint property_id, GValue *value, 136 | GParamSpec *pspec) { 137 | i3ipcCon *self = I3IPC_CON(object); 138 | 139 | switch (property_id) { 140 | case PROP_ID: 141 | g_value_set_ulong(value, self->priv->id); 142 | break; 143 | 144 | case PROP_NAME: 145 | g_value_set_string(value, self->priv->name); 146 | break; 147 | 148 | case PROP_BORDER: 149 | g_value_set_string(value, self->priv->border); 150 | break; 151 | 152 | case PROP_CURRENT_BORDER_WIDTH: 153 | g_value_set_int(value, self->priv->current_border_width); 154 | break; 155 | 156 | case PROP_LAYOUT: 157 | g_value_set_string(value, self->priv->layout); 158 | break; 159 | 160 | case PROP_ORIENTATION: 161 | g_value_set_string(value, self->priv->orientation); 162 | break; 163 | 164 | case PROP_PERCENT: 165 | g_value_set_double(value, self->priv->percent); 166 | break; 167 | 168 | case PROP_WINDOW: 169 | g_value_set_uint(value, self->priv->window); 170 | break; 171 | 172 | case PROP_URGENT: 173 | g_value_set_boolean(value, self->priv->urgent); 174 | break; 175 | 176 | case PROP_FOCUSED: 177 | g_value_set_boolean(value, self->priv->focused); 178 | break; 179 | 180 | case PROP_FULLSCREEN_MODE: 181 | g_value_set_boolean(value, self->priv->fullscreen_mode); 182 | break; 183 | 184 | case PROP_TYPE: 185 | g_value_set_string(value, self->priv->type); 186 | break; 187 | 188 | case PROP_WINDOW_CLASS: 189 | g_value_set_string(value, self->priv->window_class); 190 | break; 191 | 192 | case PROP_WINDOW_ROLE: 193 | g_value_set_string(value, self->priv->window_role); 194 | break; 195 | 196 | case PROP_WINDOW_INSTANCE: 197 | g_value_set_string(value, self->priv->window_instance); 198 | break; 199 | 200 | case PROP_MARK: 201 | g_value_set_string(value, self->priv->mark); 202 | break; 203 | 204 | case PROP_RECT: 205 | g_value_set_boxed(value, self->priv->rect); 206 | break; 207 | 208 | case PROP_DECO_RECT: 209 | g_value_set_boxed(value, self->priv->deco_rect); 210 | break; 211 | 212 | case PROP_PARENT: 213 | g_value_set_object(value, self->priv->parent); 214 | break; 215 | 216 | case PROP_NODES: 217 | g_value_set_pointer(value, self->priv->nodes); 218 | break; 219 | 220 | case PROP_FLOATING_NODES: 221 | g_value_set_pointer(value, self->priv->floating_nodes); 222 | break; 223 | 224 | case PROP_FOCUS: 225 | g_value_set_pointer(value, self->priv->focus); 226 | break; 227 | 228 | default: 229 | G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); 230 | break; 231 | } 232 | } 233 | 234 | static void i3ipc_con_parent_weak_notify(gpointer data, GObject *object) { 235 | i3ipcCon *con = I3IPC_CON(data); 236 | con->priv->parent = NULL; 237 | } 238 | 239 | static void i3ipc_con_dispose(GObject *gobject) { 240 | i3ipcCon *self = I3IPC_CON(gobject); 241 | 242 | if (self->priv->parent) { 243 | g_object_weak_unref(G_OBJECT(self->priv->parent), i3ipc_con_parent_weak_notify, self); 244 | self->priv->parent = NULL; 245 | } 246 | 247 | self->priv->rect = (i3ipc_rect_free(self->priv->rect), NULL); 248 | self->priv->deco_rect = (i3ipc_rect_free(self->priv->deco_rect), NULL); 249 | 250 | G_OBJECT_CLASS(i3ipc_con_parent_class)->dispose(gobject); 251 | } 252 | 253 | static void i3ipc_con_list_free_func(gpointer data) { 254 | if (data != NULL && I3IPC_IS_CON(data)) { 255 | g_clear_object(&data); 256 | } 257 | } 258 | 259 | static void i3ipc_con_finalize(GObject *gobject) { 260 | i3ipcCon *self = I3IPC_CON(gobject); 261 | 262 | g_free(self->priv->layout); 263 | g_free(self->priv->orientation); 264 | g_free(self->priv->name); 265 | g_free(self->priv->border); 266 | g_free(self->priv->type); 267 | g_free(self->priv->window_class); 268 | g_free(self->priv->window_role); 269 | g_free(self->priv->window_instance); 270 | g_free(self->priv->mark); 271 | 272 | g_object_unref(self->priv->conn); 273 | 274 | if (self->priv->nodes) { 275 | g_list_free_full(self->priv->nodes, i3ipc_con_list_free_func); 276 | } 277 | 278 | if (self->priv->floating_nodes) { 279 | g_list_free_full(self->priv->floating_nodes, i3ipc_con_list_free_func); 280 | } 281 | 282 | if (self->priv->focus) { 283 | g_list_free(self->priv->focus); 284 | } 285 | 286 | G_OBJECT_CLASS(i3ipc_con_parent_class)->finalize(gobject); 287 | } 288 | 289 | static void i3ipc_con_class_init(i3ipcConClass *klass) { 290 | GObjectClass *gobject_class = G_OBJECT_CLASS(klass); 291 | 292 | gobject_class->set_property = i3ipc_con_set_property; 293 | gobject_class->get_property = i3ipc_con_get_property; 294 | gobject_class->dispose = i3ipc_con_dispose; 295 | gobject_class->finalize = i3ipc_con_finalize; 296 | 297 | /** 298 | * i3ipcCon:id: 299 | */ 300 | obj_properties[PROP_ID] = 301 | g_param_spec_ulong("id", "Con id", 302 | "The internal ID (actually a C pointer value) of this container. Do not " 303 | "make any assumptions about it. You can use it to (re-)identify and " 304 | "address containers when talking to i3.", 305 | 0, /* to -> */ G_MAXULONG, 0, /* default */ 306 | G_PARAM_READABLE); 307 | 308 | obj_properties[PROP_NAME] = g_param_spec_string( 309 | "name", "Con name", 310 | "The internal name of this container. For all containers which are part of the tree " 311 | "structure down to the workspace contents, this is set to a nice human-readable name of " 312 | "the container. For all other containers, the content is not defined (yet).", 313 | "", /* default */ 314 | G_PARAM_READABLE); 315 | 316 | obj_properties[PROP_BORDER] = 317 | g_param_spec_string("border", 318 | "Can be either \"normal\", \"none\" or \"1pixel\", dependending on the " 319 | "container’s border style.", 320 | "Set/get the con's border style", "", /* default */ 321 | G_PARAM_READABLE); 322 | 323 | obj_properties[PROP_CURRENT_BORDER_WIDTH] = g_param_spec_int( 324 | "current-border-width", "Con current border width", "Number of pixels of the border width.", 325 | 0, /* to -> */ G_MAXINT, 0, /* default */ 326 | G_PARAM_READABLE); 327 | 328 | obj_properties[PROP_LAYOUT] = g_param_spec_string( 329 | "layout", "Con layout", 330 | "Can be either \"splith\", \"splitv\", \"stacked\", \"tabbed\", \"dockarea\" or " 331 | "\"output\". Other values might be possible in the future, should we add new layouts.", 332 | "", /* default */ 333 | G_PARAM_READABLE); 334 | 335 | obj_properties[PROP_ORIENTATION] = 336 | g_param_spec_string("orientation", "Con orientation", 337 | "Can be either \"none\" (for non-split containers), \"horizontal\" or " 338 | "\"vertical\". THIS FIELD IS OBSOLETE. It is still present, but your " 339 | "code should not use it. Instead, rely on the layout field.", 340 | "", /* default */ 341 | G_PARAM_READABLE); 342 | 343 | obj_properties[PROP_PERCENT] = 344 | g_param_spec_float("percent", "Con percent", 345 | "The percentage which this container takes in its parent. A value of " 346 | "null means that the percent property does not make sense for this " 347 | "container, for example for the root container.", 348 | 0, /* to -> */ G_MAXFLOAT, 0, /* default */ 349 | G_PARAM_READABLE); 350 | 351 | obj_properties[PROP_WINDOW] = g_param_spec_uint( 352 | "window", "Con window", 353 | "The X11 window ID of the actual client window inside this container. This field is set to " 354 | "null for split containers or otherwise empty containers. This ID corresponds to what " 355 | "xwininfo(1) and other X11-related tools display (usually in hex).", 356 | 0, /* to -> */ G_MAXUINT, 0, /* default */ 357 | G_PARAM_READABLE); 358 | 359 | obj_properties[PROP_URGENT] = g_param_spec_boolean( 360 | "urgent", "Con urgent value", 361 | "Whether this container (window or workspace) has the urgency hint set.", 362 | FALSE, /* default */ 363 | G_PARAM_READABLE); 364 | 365 | obj_properties[PROP_FOCUSED] = 366 | g_param_spec_boolean("focused", "Con focused", 367 | "Whether this container is currently focused.", FALSE, /* default */ 368 | G_PARAM_READABLE); 369 | 370 | obj_properties[PROP_FULLSCREEN_MODE] = g_param_spec_boolean( 371 | "fullscreen-mode", "Con fullscreen mode", 372 | "Whether this container is currently in fullscreen mode.", FALSE, /* default */ 373 | G_PARAM_READABLE); 374 | 375 | obj_properties[PROP_TYPE] = 376 | g_param_spec_string("type", "Con type", "What type of container this is", "", /* default */ 377 | G_PARAM_READABLE); 378 | 379 | obj_properties[PROP_WINDOW_CLASS] = 380 | g_param_spec_string("window_class", "Con window class", 381 | "The class of the window according to WM_CLASS", "", /* default */ 382 | G_PARAM_READABLE); 383 | 384 | obj_properties[PROP_WINDOW_ROLE] = 385 | g_param_spec_string("window_role", "Con window role", 386 | "The role of the window according to WM_WINDOW_ROLE", "", /* default */ 387 | G_PARAM_READABLE); 388 | 389 | obj_properties[PROP_WINDOW_INSTANCE] = 390 | g_param_spec_string("window_instance", "Con window instance", 391 | "The instance of the window according to WM_CLASS", "", /* default */ 392 | G_PARAM_READABLE); 393 | 394 | obj_properties[PROP_MARK] = 395 | g_param_spec_string("mark", "Con mark", "The mark of con", "", /* default */ 396 | G_PARAM_READABLE); 397 | 398 | obj_properties[PROP_PARENT] = g_param_spec_object("parent", "Con parent", "The con's parent", 399 | I3IPC_TYPE_CON, G_PARAM_READABLE); 400 | 401 | obj_properties[PROP_RECT] = 402 | g_param_spec_boxed("rect", "Con rect", "The con's rect", I3IPC_TYPE_RECT, G_PARAM_READABLE); 403 | 404 | obj_properties[PROP_DECO_RECT] = g_param_spec_boxed( 405 | "deco_rect", "Con deco rect", "The con's deco rect", I3IPC_TYPE_RECT, G_PARAM_READABLE); 406 | 407 | /** 408 | * i3ipcCon:nodes: (type GList(i3ipcCon)): 409 | * 410 | * This property is a list of the con's nodes. 411 | */ 412 | obj_properties[PROP_NODES] = 413 | g_param_spec_pointer("nodes", "Con nodes", "The con's nodes", G_PARAM_READABLE); 414 | /** 415 | * i3ipcCon:floating-nodes: (type GList(i3ipcCon)): 416 | * 417 | * This property is a list of the con's floating nodes. 418 | */ 419 | obj_properties[PROP_FLOATING_NODES] = g_param_spec_pointer( 420 | "floating-nodes", "Con floating nodes", "The con's floating nodes", G_PARAM_READABLE); 421 | 422 | /** 423 | * i3ipcCon:focus: (type GList(gulong)): 424 | * 425 | * This property is a list of con ids that represents the focus stack of 426 | * child nodes within this con. The top id in this list is the focused or 427 | * focused-inactive con within this container. 428 | */ 429 | obj_properties[PROP_FOCUS] = g_param_spec_pointer( 430 | "focus", "Con focus", 431 | "A list of con ids that represents the focus stack of child nodes within this con. The top " 432 | "id in this list is the focused or focused-inactive con within this container", 433 | G_PARAM_READABLE); 434 | 435 | g_object_class_install_properties(gobject_class, N_PROPERTIES, obj_properties); 436 | } 437 | 438 | static void i3ipc_con_init(i3ipcCon *self) { 439 | self->priv = i3ipc_con_get_instance_private(self); 440 | self->priv->rect = g_slice_new0(i3ipcRect); 441 | self->priv->deco_rect = g_slice_new0(i3ipcRect); 442 | self->priv->nodes = NULL; 443 | self->priv->floating_nodes = NULL; 444 | self->priv->focus = NULL; 445 | } 446 | 447 | static void i3ipc_con_initialize_nodes(JsonArray *array, guint index_, JsonNode *element_node, 448 | gpointer user_data) { 449 | i3ipcCon *parent = I3IPC_CON(user_data); 450 | JsonObject *data = json_node_get_object(element_node); 451 | 452 | i3ipcCon *con = i3ipc_con_new(parent, data, parent->priv->conn); 453 | 454 | parent->priv->nodes = g_list_append(parent->priv->nodes, con); 455 | } 456 | 457 | static void i3ipc_con_initialize_floating_nodes(JsonArray *array, guint index_, 458 | JsonNode *element_node, gpointer user_data) { 459 | i3ipcCon *parent = I3IPC_CON(user_data); 460 | JsonObject *data = json_node_get_object(element_node); 461 | 462 | i3ipcCon *con = i3ipc_con_new(parent, data, parent->priv->conn); 463 | 464 | parent->priv->floating_nodes = g_list_append(parent->priv->floating_nodes, con); 465 | } 466 | 467 | i3ipcCon *i3ipc_con_new(i3ipcCon *parent, JsonObject *data, i3ipcConnection *conn) { 468 | i3ipcCon *con; 469 | con = g_object_new(I3IPC_TYPE_CON, NULL); 470 | 471 | g_object_ref(conn); 472 | con->priv->conn = conn; 473 | 474 | if (!json_object_get_null_member(data, "percent")) { 475 | con->priv->percent = json_object_get_double_member(data, "percent"); 476 | } 477 | 478 | if (!json_object_get_null_member(data, "window")) { 479 | con->priv->window = json_object_get_int_member(data, "window"); 480 | } 481 | 482 | if (json_object_has_member(data, "window_properties")) { 483 | JsonObject *window_properties = json_object_get_object_member(data, "window_properties"); 484 | 485 | if (json_object_has_member(window_properties, "class")) { 486 | con->priv->window_class = 487 | g_strdup(json_object_get_string_member(window_properties, "class")); 488 | } 489 | if (json_object_has_member(window_properties, "window_role")) { 490 | con->priv->window_role = 491 | g_strdup(json_object_get_string_member(window_properties, "window_role")); 492 | } 493 | if (json_object_has_member(window_properties, "instance")) { 494 | con->priv->window_instance = 495 | g_strdup(json_object_get_string_member(window_properties, "instance")); 496 | } 497 | } 498 | 499 | if (json_object_has_member(data, "mark")) { 500 | con->priv->mark = g_strdup(json_object_get_string_member(data, "mark")); 501 | } 502 | 503 | con->priv->name = g_strdup(json_object_get_string_member(data, "name")); 504 | con->priv->focused = json_object_get_boolean_member(data, "focused"); 505 | con->priv->fullscreen_mode = json_object_get_boolean_member(data, "fullscreen_mode"); 506 | con->priv->urgent = json_object_get_boolean_member(data, "urgent"); 507 | con->priv->layout = g_strdup(json_object_get_string_member(data, "layout")); 508 | con->priv->orientation = g_strdup(json_object_get_string_member(data, "orientation")); 509 | con->priv->current_border_width = json_object_get_int_member(data, "current_border_width"); 510 | con->priv->border = g_strdup(json_object_get_string_member(data, "border")); 511 | con->priv->id = json_object_get_int_member(data, "id"); 512 | 513 | JsonNode *con_type_node = json_object_get_member(data, "type"); 514 | 515 | /* XXX: In the development version, the "type" property is a string of the 516 | * type, but in the current stable version (4.7.2) it is an integer as 517 | * defined in i3's data header. When the next version comes out, the case 518 | * where type is a number should be removed. */ 519 | if (json_node_get_value_type(con_type_node) == G_TYPE_STRING) { 520 | con->priv->type = g_strdup(json_node_get_string(con_type_node)); 521 | } else { 522 | int con_type_int = (int)json_node_get_int(con_type_node); 523 | switch (con_type_int) { 524 | case 0: 525 | con->priv->type = g_strdup("root"); 526 | break; 527 | case 1: 528 | con->priv->type = g_strdup("output"); 529 | break; 530 | case 2: 531 | case 3: 532 | con->priv->type = g_strdup("con"); 533 | break; 534 | case 4: 535 | con->priv->type = g_strdup("workspace"); 536 | break; 537 | case 5: 538 | con->priv->type = g_strdup("dockarea"); 539 | break; 540 | } 541 | } 542 | 543 | if (parent) { 544 | g_object_weak_ref(G_OBJECT(parent), i3ipc_con_parent_weak_notify, con); 545 | con->priv->parent = parent; 546 | } 547 | 548 | JsonObject *rect_data = json_object_get_object_member(data, "rect"); 549 | 550 | con->priv->rect->x = json_object_get_int_member(rect_data, "x"); 551 | con->priv->rect->y = json_object_get_int_member(rect_data, "y"); 552 | con->priv->rect->width = json_object_get_int_member(rect_data, "width"); 553 | con->priv->rect->height = json_object_get_int_member(rect_data, "height"); 554 | 555 | if (json_object_has_member(data, "deco_rect")) { 556 | JsonObject *deco_rect_data = json_object_get_object_member(data, "deco_rect"); 557 | 558 | con->priv->deco_rect->x = json_object_get_int_member(deco_rect_data, "x"); 559 | con->priv->deco_rect->y = json_object_get_int_member(deco_rect_data, "y"); 560 | con->priv->deco_rect->width = json_object_get_int_member(deco_rect_data, "width"); 561 | con->priv->deco_rect->height = json_object_get_int_member(deco_rect_data, "height"); 562 | } 563 | 564 | JsonArray *nodes_array = json_object_get_array_member(data, "nodes"); 565 | json_array_foreach_element(nodes_array, i3ipc_con_initialize_nodes, con); 566 | 567 | JsonArray *floating_nodes_array = json_object_get_array_member(data, "floating_nodes"); 568 | json_array_foreach_element(floating_nodes_array, i3ipc_con_initialize_floating_nodes, con); 569 | 570 | JsonArray *focus_array = json_object_get_array_member(data, "focus"); 571 | guint len = json_array_get_length(focus_array); 572 | for (int i = 0; i < len; i += 1) { 573 | con->priv->focus = g_list_append( 574 | con->priv->focus, GINT_TO_POINTER(json_array_get_int_element(focus_array, i))); 575 | } 576 | 577 | return con; 578 | } 579 | 580 | /** 581 | * i3ipc_con_get_nodes: 582 | * @self: an #i3ipcCon 583 | * 584 | * Returns: (transfer none) (element-type i3ipcCon): A list of child nodes. 585 | */ 586 | const GList *i3ipc_con_get_nodes(i3ipcCon *self) { 587 | return self->priv->nodes; 588 | } 589 | 590 | /** 591 | * i3ipc_con_get_floating_nodes: 592 | * @self: an #i3ipcCon 593 | * 594 | * Returns: (transfer none) (element-type i3ipcCon): A list of child floating nodes. 595 | */ 596 | const GList *i3ipc_con_get_floating_nodes(i3ipcCon *self) { 597 | return self->priv->floating_nodes; 598 | } 599 | 600 | /** 601 | * i3ipc_con_root: 602 | * @self: an #i3ipcCon 603 | * 604 | * Returns: (transfer none): The root node of the tree. 605 | */ 606 | i3ipcCon *i3ipc_con_root(i3ipcCon *self) { 607 | i3ipcCon *retval = self; 608 | i3ipcCon *parent = self->priv->parent; 609 | 610 | while (parent != NULL) { 611 | parent = retval->priv->parent; 612 | 613 | if (parent != NULL) { 614 | retval = parent; 615 | } 616 | } 617 | 618 | return retval; 619 | } 620 | 621 | static void i3ipc_con_collect_descendents_func(gpointer data, gpointer user_data) { 622 | i3ipcCon *con = I3IPC_CON(data); 623 | GList *descendents = (GList *)user_data; 624 | 625 | descendents = g_list_append(descendents, con); 626 | 627 | if (descendents != NULL) { 628 | g_list_foreach(con->priv->nodes, i3ipc_con_collect_descendents_func, descendents); 629 | g_list_foreach(con->priv->floating_nodes, i3ipc_con_collect_descendents_func, descendents); 630 | } 631 | } 632 | 633 | /** 634 | * i3ipc_con_descendents: 635 | * @self: an #i3ipcCon 636 | * 637 | * Returns: (transfer container) (element-type i3ipcCon): a list of descendent nodes 638 | */ 639 | GList *i3ipc_con_descendents(i3ipcCon *self) { 640 | GList *retval; 641 | 642 | /* if the con is a leaf, there is nothing to do */ 643 | if (!self->priv->nodes && !self->priv->floating_nodes) { 644 | return NULL; 645 | } 646 | 647 | /* the list has to have a first element for some reason. */ 648 | retval = g_list_alloc(); 649 | 650 | g_list_foreach(self->priv->nodes, i3ipc_con_collect_descendents_func, retval); 651 | g_list_foreach(self->priv->floating_nodes, i3ipc_con_collect_descendents_func, retval); 652 | 653 | retval = g_list_delete_link(retval, g_list_first(retval)); 654 | 655 | return retval; 656 | } 657 | 658 | /** 659 | * i3ipc_con_leaves: 660 | * @self: an #i3ipcCon 661 | * 662 | * Finds the leaf descendent nodes of a given container excluding dock clients. 663 | * 664 | * Returns: (transfer container) (element-type i3ipcCon): a list of leaf descendent nodes 665 | */ 666 | GList *i3ipc_con_leaves(i3ipcCon *self) { 667 | GList *descendents; 668 | GList *retval = NULL; 669 | 670 | descendents = i3ipc_con_descendents(self); 671 | guint len = g_list_length(descendents); 672 | 673 | for (gint i = 0; i < len; i += 1) { 674 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 675 | 676 | if (g_list_length(con->priv->nodes) == 0 && g_strcmp0(con->priv->type, "con") == 0 && 677 | g_strcmp0(con->priv->parent->priv->type, "dockarea") != 0) { 678 | retval = g_list_append(retval, con); 679 | } 680 | } 681 | 682 | g_list_free(descendents); 683 | 684 | return retval; 685 | } 686 | 687 | /** 688 | * i3ipc_con_get_name: 689 | * @self: an #i3ipcCon 690 | * 691 | * Convenience function to get the commonly-needed "name" property of the Con. 692 | * 693 | * Returns: (transfer none): The "name" property of the Con 694 | */ 695 | const gchar *i3ipc_con_get_name(i3ipcCon *self) { 696 | return self->priv->name; 697 | } 698 | 699 | /** 700 | * i3ipc_con_command: 701 | * @self: an #i3ipcCon 702 | * @command: the command to execute on the con 703 | * @err (allow-none): the location of a GError or NULL 704 | * 705 | * Convenience function to execute a command in the context of the container 706 | * (it will be selected by criteria) 707 | * 708 | */ 709 | void i3ipc_con_command(i3ipcCon *self, const gchar *command, GError **err) { 710 | gchar *reply; 711 | gchar *context_command; 712 | GError *tmp_error = NULL; 713 | 714 | g_return_if_fail(err == NULL || *err == NULL); 715 | 716 | context_command = g_strdup_printf("[con_id=\"%lu\"] %s", self->priv->id, command); 717 | 718 | reply = i3ipc_connection_message(self->priv->conn, I3IPC_MESSAGE_TYPE_COMMAND, context_command, 719 | &tmp_error); 720 | 721 | if (tmp_error != NULL) { 722 | g_propagate_error(err, tmp_error); 723 | } 724 | 725 | g_free(reply); 726 | g_free(context_command); 727 | } 728 | 729 | /** 730 | * i3ipc_con_command_children: 731 | * @self: an #i3ipcCon 732 | * @command: the command to execute on the con's nodes 733 | * @err: (allow-none): the location of a GError or NULL 734 | * 735 | * Convenience function to execute a command in the context of the container's 736 | * children (the immediate descendents will be selected by criteria) 737 | * 738 | */ 739 | void i3ipc_con_command_children(i3ipcCon *self, const gchar *command, GError **err) { 740 | guint len; 741 | gchar *reply; 742 | GString *payload; 743 | GError *tmp_error = NULL; 744 | 745 | len = g_list_length(self->priv->nodes); 746 | 747 | if (len == 0) { 748 | return; 749 | } 750 | 751 | payload = g_string_new(""); 752 | 753 | for (gint i = 0; i < len; i += 1) { 754 | g_string_append_printf(payload, "[con_id=\"%lu\"] %s; ", 755 | I3IPC_CON(g_list_nth_data(self->priv->nodes, i))->priv->id, command); 756 | } 757 | 758 | reply = i3ipc_connection_message(self->priv->conn, I3IPC_MESSAGE_TYPE_COMMAND, payload->str, 759 | &tmp_error); 760 | 761 | if (tmp_error != NULL) { 762 | g_propagate_error(err, tmp_error); 763 | } 764 | 765 | g_free(reply); 766 | g_string_free(payload, TRUE); 767 | } 768 | 769 | static void i3ipc_con_collect_workspaces_func(gpointer data, gpointer user_data) { 770 | i3ipcCon *con = I3IPC_CON(data); 771 | GList *workspaces = (GList *)user_data; 772 | 773 | if (g_strcmp0(con->priv->type, "workspace") == 0 && !g_str_has_prefix(con->priv->name, "__")) { 774 | workspaces = g_list_append(workspaces, con); 775 | } else if (workspaces != NULL) { 776 | g_list_foreach(con->priv->nodes, i3ipc_con_collect_workspaces_func, workspaces); 777 | } 778 | } 779 | 780 | /** 781 | * i3ipc_con_workspaces: 782 | * @self: an #i3ipcCon 783 | * 784 | * Returns: (transfer container) (element-type i3ipcCon): a list of workspaces in the tree 785 | */ 786 | GList *i3ipc_con_workspaces(i3ipcCon *self) { 787 | GList *retval; 788 | i3ipcCon *root; 789 | 790 | root = i3ipc_con_root(self); 791 | 792 | /* this could happen for incomplete trees */ 793 | if (!root->priv->nodes) { 794 | return NULL; 795 | } 796 | 797 | /* the list has to have a first element for some reason. */ 798 | retval = g_list_alloc(); 799 | 800 | g_list_foreach(root->priv->nodes, i3ipc_con_collect_workspaces_func, retval); 801 | 802 | /* XXX: I hope this doesn't leak */ 803 | retval = g_list_remove_link(retval, g_list_first(retval)); 804 | 805 | return retval; 806 | } 807 | 808 | static gint i3ipc_con_focused_cmp_func(gconstpointer a, gconstpointer b) { 809 | const i3ipcCon *con = a; 810 | 811 | return con->priv->focused ? 0 : 1; 812 | } 813 | 814 | /** 815 | * i3ipc_con_find_focused: 816 | * @self: an #i3ipcCon 817 | * 818 | * Returns: (transfer none): The focused Con, or NULL if not found in this Con. 819 | * 820 | */ 821 | i3ipcCon *i3ipc_con_find_focused(i3ipcCon *self) { 822 | GList *descendents; 823 | GList *cmp_result; 824 | i3ipcCon *retval = NULL; 825 | 826 | descendents = i3ipc_con_descendents(self); 827 | 828 | if (descendents == NULL) { 829 | return NULL; 830 | } 831 | 832 | cmp_result = g_list_find_custom(descendents, NULL, i3ipc_con_focused_cmp_func); 833 | 834 | if (cmp_result != NULL) { 835 | retval = I3IPC_CON(cmp_result->data); 836 | } 837 | 838 | g_list_free(descendents); 839 | 840 | return retval; 841 | } 842 | 843 | /** 844 | * i3ipc_con_find_by_id: 845 | * @self: an #i3ipcCon 846 | * @con_id: the id of the con to find 847 | * 848 | * Returns: (transfer none): The con with the given con_id among this con's descendents 849 | */ 850 | i3ipcCon *i3ipc_con_find_by_id(i3ipcCon *self, const gulong con_id) { 851 | GList *descendents; 852 | i3ipcCon *retval = NULL; 853 | 854 | descendents = i3ipc_con_descendents(self); 855 | guint len = g_list_length(descendents); 856 | 857 | for (gint i = 0; i < len; i += 1) { 858 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 859 | 860 | if (con->priv->id == con_id) { 861 | retval = con; 862 | break; 863 | } 864 | } 865 | 866 | g_list_free(descendents); 867 | 868 | return retval; 869 | } 870 | 871 | /** 872 | * i3ipc_con_find_by_window: 873 | * @self: an #i3ipcCon 874 | * @window_id: the window id of the con to find 875 | * 876 | * Returns: (transfer none): The con with the given window id among this con's descendents 877 | */ 878 | i3ipcCon *i3ipc_con_find_by_window(i3ipcCon *self, const guint window_id) { 879 | GList *descendents; 880 | i3ipcCon *retval = NULL; 881 | 882 | descendents = i3ipc_con_descendents(self); 883 | guint len = g_list_length(descendents); 884 | 885 | for (gint i = 0; i < len; i += 1) { 886 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 887 | 888 | if (con->priv->window == window_id) { 889 | retval = con; 890 | break; 891 | } 892 | } 893 | 894 | g_list_free(descendents); 895 | 896 | return retval; 897 | } 898 | 899 | /** 900 | * i3ipc_con_find_named: 901 | * @self: an #i3ipcCon 902 | * @pattern: a perl-compatible regular expression pattern 903 | * @err: (allow-none): return location for a GError or NULL 904 | * 905 | * Returns: (transfer container) (element-type i3ipcCon): A list of descendent Cons which have a 906 | * name that matches the pattern 907 | */ 908 | GList *i3ipc_con_find_named(i3ipcCon *self, const gchar *pattern, GError **err) { 909 | GList *descendents; 910 | GRegex *regex; 911 | GList *retval = NULL; 912 | GError *tmp_error = NULL; 913 | 914 | g_return_val_if_fail(err == NULL || *err == NULL, NULL); 915 | 916 | regex = g_regex_new(pattern, 0, 0, &tmp_error); 917 | 918 | if (tmp_error != NULL) { 919 | g_propagate_error(err, tmp_error); 920 | return NULL; 921 | } 922 | 923 | descendents = i3ipc_con_descendents(self); 924 | guint len = g_list_length(descendents); 925 | 926 | for (gint i = 0; i < len; i += 1) { 927 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 928 | 929 | if (g_regex_match(regex, con->priv->name, 0, NULL)) { 930 | retval = g_list_append(retval, con); 931 | } 932 | } 933 | 934 | g_list_free(descendents); 935 | g_regex_unref(regex); 936 | 937 | return retval; 938 | } 939 | 940 | /** 941 | * i3ipc_con_find_classed: 942 | * @self: an #i3ipcCon 943 | * @pattern: a perl-compatible regular expression pattern 944 | * @err: (allow-none): return location for a GError or NULL 945 | * 946 | * Returns: (transfer container) (element-type i3ipcCon): A list of descendent Cons which have a 947 | * WM_CLASS class property that matches the pattern 948 | */ 949 | GList *i3ipc_con_find_classed(i3ipcCon *self, const gchar *pattern, GError **err) { 950 | GList *descendents; 951 | GRegex *regex; 952 | GList *retval = NULL; 953 | GError *tmp_error = NULL; 954 | 955 | g_return_val_if_fail(err == NULL || *err == NULL, NULL); 956 | 957 | regex = g_regex_new(pattern, 0, 0, &tmp_error); 958 | 959 | if (tmp_error != NULL) { 960 | g_propagate_error(err, tmp_error); 961 | return NULL; 962 | } 963 | 964 | descendents = i3ipc_con_descendents(self); 965 | guint len = g_list_length(descendents); 966 | 967 | for (gint i = 0; i < len; i += 1) { 968 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 969 | 970 | if (con->priv->window_class && g_regex_match(regex, con->priv->window_class, 0, NULL)) { 971 | retval = g_list_append(retval, con); 972 | } 973 | } 974 | 975 | g_list_free(descendents); 976 | g_regex_unref(regex); 977 | 978 | return retval; 979 | } 980 | 981 | /** 982 | * i3ipc_con_find_marked: 983 | * @self: an #i3ipcCon 984 | * @pattern: a perl-compatible regular expression pattern 985 | * @err: (allow-none): return location for a GError or NULL 986 | * 987 | * Returns: (transfer container) (element-type i3ipcCon): A list of descendent 988 | * Cons which have the mark that matches the pattern 989 | */ 990 | GList *i3ipc_con_find_marked(i3ipcCon *self, const gchar *pattern, GError **err) { 991 | GList *descendents; 992 | GRegex *regex; 993 | GList *retval = NULL; 994 | GError *tmp_error = NULL; 995 | 996 | g_return_val_if_fail(err == NULL || *err == NULL, NULL); 997 | 998 | regex = g_regex_new(pattern, 0, 0, &tmp_error); 999 | 1000 | if (tmp_error != NULL) { 1001 | g_propagate_error(err, tmp_error); 1002 | return NULL; 1003 | } 1004 | 1005 | descendents = i3ipc_con_descendents(self); 1006 | guint len = g_list_length(descendents); 1007 | 1008 | for (gint i = 0; i < len; i += 1) { 1009 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(descendents, i)); 1010 | 1011 | if (con->priv->mark && g_regex_match(regex, con->priv->mark, 0, NULL)) { 1012 | retval = g_list_append(retval, con); 1013 | } 1014 | } 1015 | 1016 | g_list_free(descendents); 1017 | g_regex_unref(regex); 1018 | 1019 | return retval; 1020 | } 1021 | 1022 | /** 1023 | * i3ipc_con_workspace: 1024 | * @self: an #i3ipcCon 1025 | * 1026 | * Returns: (transfer none): The closest workspace con 1027 | */ 1028 | i3ipcCon *i3ipc_con_workspace(i3ipcCon *self) { 1029 | i3ipcCon *retval = self->priv->parent; 1030 | 1031 | while (retval != NULL) { 1032 | if (g_strcmp0(retval->priv->type, "workspace") == 0) { 1033 | break; 1034 | } 1035 | 1036 | retval = retval->priv->parent; 1037 | } 1038 | 1039 | return retval; 1040 | } 1041 | 1042 | /** 1043 | * i3ipc_con_scratchpad: 1044 | * @self: an #i3ipcCon 1045 | * 1046 | * Returns: (transfer none): The scratchpad workspace con 1047 | */ 1048 | i3ipcCon *i3ipc_con_scratchpad(i3ipcCon *self) { 1049 | i3ipcCon *retval = NULL; 1050 | /* start from the root */ 1051 | i3ipcCon *root = i3ipc_con_root(self); 1052 | 1053 | guint len = g_list_length(root->priv->nodes); 1054 | 1055 | /* first look for the internal "__i3" con */ 1056 | i3ipcCon *i3con = NULL; 1057 | 1058 | for (gint i = 0; i < len; i += 1) { 1059 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(root->priv->nodes, i)); 1060 | 1061 | if (g_strcmp0(con->priv->name, "__i3") == 0) { 1062 | i3con = con; 1063 | break; 1064 | } 1065 | } 1066 | 1067 | /* next we need to find the content con */ 1068 | i3ipcCon *i3con_content = NULL; 1069 | 1070 | if (i3con != NULL) { 1071 | len = g_list_length(i3con->priv->nodes); 1072 | for (gint i = 0; i < len; i += 1) { 1073 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(i3con->priv->nodes, i)); 1074 | if (g_strcmp0(con->priv->name, "content") == 0) { 1075 | i3con_content = con; 1076 | break; 1077 | } 1078 | } 1079 | } 1080 | 1081 | /* the scratchpad is within the this content con */ 1082 | if (i3con_content != NULL) { 1083 | len = g_list_length(i3con_content->priv->nodes); 1084 | for (gint i = 0; i < len; i += 1) { 1085 | i3ipcCon *con = I3IPC_CON(g_list_nth_data(i3con_content->priv->nodes, i)); 1086 | if (g_strcmp0(con->priv->name, "__i3_scratch") == 0) { 1087 | retval = con; 1088 | break; 1089 | } 1090 | } 1091 | } 1092 | 1093 | return retval; 1094 | } 1095 | --------------------------------------------------------------------------------