Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
39329c2ce8 |
66
IPCClient.c
66
IPCClient.c
@ -1,66 +0,0 @@
|
|||||||
#include "IPCClient.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
IPCClient *
|
|
||||||
ipc_client_new(int fd)
|
|
||||||
{
|
|
||||||
IPCClient *c = (IPCClient *)malloc(sizeof(IPCClient));
|
|
||||||
|
|
||||||
if (c == NULL) return NULL;
|
|
||||||
|
|
||||||
// Initialize struct
|
|
||||||
memset(&c->event, 0, sizeof(struct epoll_event));
|
|
||||||
|
|
||||||
c->buffer_size = 0;
|
|
||||||
c->buffer = NULL;
|
|
||||||
c->fd = fd;
|
|
||||||
c->event.data.fd = fd;
|
|
||||||
c->next = NULL;
|
|
||||||
c->prev = NULL;
|
|
||||||
c->subscriptions = 0;
|
|
||||||
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ipc_list_add_client(IPCClientList *list, IPCClient *nc)
|
|
||||||
{
|
|
||||||
DEBUG("Adding client with fd %d to list\n", nc->fd);
|
|
||||||
|
|
||||||
if (*list == NULL) {
|
|
||||||
// List is empty, point list at first client
|
|
||||||
*list = nc;
|
|
||||||
} else {
|
|
||||||
IPCClient *c;
|
|
||||||
// Go to last client in list
|
|
||||||
for (c = *list; c && c->next; c = c->next)
|
|
||||||
;
|
|
||||||
c->next = nc;
|
|
||||||
nc->prev = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ipc_list_remove_client(IPCClientList *list, IPCClient *c)
|
|
||||||
{
|
|
||||||
IPCClient *cprev = c->prev;
|
|
||||||
IPCClient *cnext = c->next;
|
|
||||||
|
|
||||||
if (cprev != NULL) cprev->next = c->next;
|
|
||||||
if (cnext != NULL) cnext->prev = c->prev;
|
|
||||||
if (c == *list) *list = c->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPCClient *
|
|
||||||
ipc_list_get_client(IPCClientList list, int fd)
|
|
||||||
{
|
|
||||||
for (IPCClient *c = list; c; c = c->next) {
|
|
||||||
if (c->fd == fd) return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
61
IPCClient.h
61
IPCClient.h
@ -1,61 +0,0 @@
|
|||||||
#ifndef IPC_CLIENT_H_
|
|
||||||
#define IPC_CLIENT_H_
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
|
|
||||||
typedef struct IPCClient IPCClient;
|
|
||||||
/**
|
|
||||||
* This structure contains the details of an IPC Client and pointers for a
|
|
||||||
* linked list
|
|
||||||
*/
|
|
||||||
struct IPCClient {
|
|
||||||
int fd;
|
|
||||||
int subscriptions;
|
|
||||||
|
|
||||||
char *buffer;
|
|
||||||
uint32_t buffer_size;
|
|
||||||
|
|
||||||
struct epoll_event event;
|
|
||||||
IPCClient *next;
|
|
||||||
IPCClient *prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef IPCClient *IPCClientList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocate memory for new IPCClient with the specified file descriptor and
|
|
||||||
* initialize struct.
|
|
||||||
*
|
|
||||||
* @param fd File descriptor of IPC client
|
|
||||||
*
|
|
||||||
* @return Address to allocated IPCClient struct
|
|
||||||
*/
|
|
||||||
IPCClient *ipc_client_new(int fd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an IPC Client to the specified list
|
|
||||||
*
|
|
||||||
* @param list Address of the list to add the client to
|
|
||||||
* @param nc Address of the IPCClient
|
|
||||||
*/
|
|
||||||
void ipc_list_add_client(IPCClientList *list, IPCClient *nc);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an IPCClient from the specified list
|
|
||||||
*
|
|
||||||
* @param list Address of the list to remove the client from
|
|
||||||
* @param c Address of the IPCClient
|
|
||||||
*/
|
|
||||||
void ipc_list_remove_client(IPCClientList *list, IPCClient *c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an IPCClient from the specified IPCClient list
|
|
||||||
*
|
|
||||||
* @param list List to remove the client from
|
|
||||||
* @param fd File descriptor of the IPCClient
|
|
||||||
*/
|
|
||||||
IPCClient *ipc_list_get_client(IPCClientList list, int fd);
|
|
||||||
|
|
||||||
#endif // IPC_CLIENT_H_
|
|
103
LICENSE
103
LICENSE
@ -1,73 +1,38 @@
|
|||||||
Apache License
|
MIT/X Consortium License
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
|
||||||
|
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
|
||||||
|
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
|
||||||
|
© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
|
||||||
|
© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
|
||||||
|
© 2007-2009 Christof Musik <christof at sendfax dot de>
|
||||||
|
© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
|
||||||
|
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
|
||||||
|
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
|
||||||
|
© 2008 Neale Pickett <neale dot woozle dot org>
|
||||||
|
© 2009 Mate Nagy <mnagy at port70 dot net>
|
||||||
|
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
|
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
© 2011 Christoph Lohmann <20h@r-36.net>
|
||||||
|
© 2015-2016 Quentin Rameau <quinq@fifth.space>
|
||||||
|
© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
|
||||||
|
© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
|
||||||
|
© 2020-2022 Chris Down <chris@chrisdown.name>
|
||||||
|
|
||||||
1. Definitions.
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
10
Makefile
10
Makefile
@ -6,7 +6,7 @@ include config.mk
|
|||||||
SRC = drw.c dwm.c util.c
|
SRC = drw.c dwm.c util.c
|
||||||
OBJ = ${SRC:.c=.o}
|
OBJ = ${SRC:.c=.o}
|
||||||
|
|
||||||
all: options dwm dwm-msg
|
all: options dwm
|
||||||
|
|
||||||
options:
|
options:
|
||||||
@echo dwm build options:
|
@echo dwm build options:
|
||||||
@ -25,11 +25,8 @@ config.h:
|
|||||||
dwm: ${OBJ}
|
dwm: ${OBJ}
|
||||||
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||||
|
|
||||||
dwm-msg: dwm-msg.o
|
|
||||||
${CC} -o $@ $< ${LDFLAGS}
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f dwm dwm-msg ${OBJ} dwm-${VERSION}.tar.gz
|
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
|
||||||
|
|
||||||
dist: clean
|
dist: clean
|
||||||
mkdir -p dwm-${VERSION}
|
mkdir -p dwm-${VERSION}
|
||||||
@ -41,9 +38,8 @@ dist: clean
|
|||||||
|
|
||||||
install: all
|
install: all
|
||||||
mkdir -p ${DESTDIR}${PREFIX}/bin
|
mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||||
cp -f dwm dwm-msg ${DESTDIR}${PREFIX}/bin
|
cp -f dwm ${DESTDIR}${PREFIX}/bin
|
||||||
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
|
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
|
||||||
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm-msg
|
|
||||||
mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||||
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||||
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||||
|
31
config.def.h
31
config.def.h
@ -11,7 +11,7 @@ static const char col_gray1[] = "#222222";
|
|||||||
static const char col_gray2[] = "#444444";
|
static const char col_gray2[] = "#444444";
|
||||||
static const char col_gray3[] = "#bbbbbb";
|
static const char col_gray3[] = "#bbbbbb";
|
||||||
static const char col_gray4[] = "#eeeeee";
|
static const char col_gray4[] = "#eeeeee";
|
||||||
static const char col_cyan[] = "#606060";
|
static const char col_cyan[] = "#005577";
|
||||||
static const char *colors[][3] = {
|
static const char *colors[][3] = {
|
||||||
/* fg bg border */
|
/* fg bg border */
|
||||||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||||
@ -45,7 +45,7 @@ static const Layout layouts[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* key definitions */
|
/* key definitions */
|
||||||
#define MODKEY Mod4Mask
|
#define MODKEY Mod1Mask
|
||||||
#define TAGKEYS(KEY,TAG) \
|
#define TAGKEYS(KEY,TAG) \
|
||||||
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||||
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||||
@ -56,11 +56,10 @@ static const Layout layouts[] = {
|
|||||||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
|
|
||||||
/* commands */
|
/* commands */
|
||||||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
|
static const char *dmenucmd[] = { "dmenu_run", "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
static const char *termcmd[] = { "st", NULL };
|
||||||
static const char *termcmd[] = { "alacritty", NULL };
|
|
||||||
|
|
||||||
static Key keys[] = {
|
static const Key keys[] = {
|
||||||
/* modifier key function argument */
|
/* modifier key function argument */
|
||||||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||||
@ -99,7 +98,7 @@ static Key keys[] = {
|
|||||||
|
|
||||||
/* button definitions */
|
/* button definitions */
|
||||||
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||||
static Button buttons[] = {
|
static const Button buttons[] = {
|
||||||
/* click event mask button function argument */
|
/* click event mask button function argument */
|
||||||
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||||
@ -114,21 +113,3 @@ static Button buttons[] = {
|
|||||||
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
|
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *ipcsockpath = "/tmp/dwm.sock";
|
|
||||||
static IPCCommand ipccommands[] = {
|
|
||||||
IPCCOMMAND( view, 1, {ARG_TYPE_UINT} ),
|
|
||||||
IPCCOMMAND( toggleview, 1, {ARG_TYPE_UINT} ),
|
|
||||||
IPCCOMMAND( tag, 1, {ARG_TYPE_UINT} ),
|
|
||||||
IPCCOMMAND( toggletag, 1, {ARG_TYPE_UINT} ),
|
|
||||||
IPCCOMMAND( tagmon, 1, {ARG_TYPE_UINT} ),
|
|
||||||
IPCCOMMAND( focusmon, 1, {ARG_TYPE_SINT} ),
|
|
||||||
IPCCOMMAND( focusstack, 1, {ARG_TYPE_SINT} ),
|
|
||||||
IPCCOMMAND( zoom, 1, {ARG_TYPE_NONE} ),
|
|
||||||
IPCCOMMAND( incnmaster, 1, {ARG_TYPE_SINT} ),
|
|
||||||
IPCCOMMAND( killclient, 1, {ARG_TYPE_SINT} ),
|
|
||||||
IPCCOMMAND( togglefloating, 1, {ARG_TYPE_NONE} ),
|
|
||||||
IPCCOMMAND( setmfact, 1, {ARG_TYPE_FLOAT} ),
|
|
||||||
IPCCOMMAND( setlayoutsafe, 1, {ARG_TYPE_PTR} ),
|
|
||||||
IPCCOMMAND( quit, 1, {ARG_TYPE_NONE} )
|
|
||||||
};
|
|
||||||
|
|
||||||
|
11
config.mk
11
config.mk
@ -1,5 +1,5 @@
|
|||||||
# dwm version
|
# dwm version
|
||||||
VERSION = 6.3
|
VERSION = 6.4
|
||||||
|
|
||||||
# Customize below to fit your system
|
# Customize below to fit your system
|
||||||
|
|
||||||
@ -19,14 +19,11 @@ FREETYPELIBS = -lfontconfig -lXft
|
|||||||
FREETYPEINC = /usr/include/freetype2
|
FREETYPEINC = /usr/include/freetype2
|
||||||
# OpenBSD (uncomment)
|
# OpenBSD (uncomment)
|
||||||
#FREETYPEINC = ${X11INC}/freetype2
|
#FREETYPEINC = ${X11INC}/freetype2
|
||||||
|
#MANPREFIX = ${PREFIX}/man
|
||||||
# yajl
|
|
||||||
YAJLLIBS = -lyajl
|
|
||||||
YAJLINC = /usr/include/yajl
|
|
||||||
|
|
||||||
# includes and libs
|
# includes and libs
|
||||||
INCS = -I${X11INC} -I${FREETYPEINC} -I${YAJLINC}
|
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||||
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} ${YAJLLIBS}
|
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||||
|
|
||||||
# flags
|
# flags
|
||||||
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||||
|
102
drw.c
102
drw.c
@ -133,19 +133,6 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
|||||||
die("no font specified.");
|
die("no font specified.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not allow using color fonts. This is a workaround for a BadLength
|
|
||||||
* error from Xft with color glyphs. Modelled on the Xterm workaround. See
|
|
||||||
* https://bugzilla.redhat.com/show_bug.cgi?id=1498269
|
|
||||||
* https://lists.suckless.org/dev/1701/30932.html
|
|
||||||
* https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=916349
|
|
||||||
* and lots more all over the internet.
|
|
||||||
*/
|
|
||||||
FcBool iscol;
|
|
||||||
if(FcPatternGetBool(xfont->pattern, FC_COLOR, 0, &iscol) == FcResultMatch && iscol) {
|
|
||||||
XftFontClose(drw->dpy, xfont);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
font = ecalloc(1, sizeof(Fnt));
|
font = ecalloc(1, sizeof(Fnt));
|
||||||
font->xfont = xfont;
|
font->xfont = xfont;
|
||||||
font->pattern = pattern;
|
font->pattern = pattern;
|
||||||
@ -251,12 +238,10 @@ drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int
|
|||||||
int
|
int
|
||||||
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
int i, ty, ellipsis_x = 0;
|
||||||
int ty;
|
unsigned int tmpw, ew, ellipsis_w = 0, ellipsis_len;
|
||||||
unsigned int ew;
|
|
||||||
XftDraw *d = NULL;
|
XftDraw *d = NULL;
|
||||||
Fnt *usedfont, *curfont, *nextfont;
|
Fnt *usedfont, *curfont, *nextfont;
|
||||||
size_t i, len;
|
|
||||||
int utf8strlen, utf8charlen, render = x || y || w || h;
|
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||||
long utf8codepoint = 0;
|
long utf8codepoint = 0;
|
||||||
const char *utf8str;
|
const char *utf8str;
|
||||||
@ -264,13 +249,17 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
FcPattern *fcpattern;
|
FcPattern *fcpattern;
|
||||||
FcPattern *match;
|
FcPattern *match;
|
||||||
XftResult result;
|
XftResult result;
|
||||||
int charexists = 0;
|
int charexists = 0, overflow = 0;
|
||||||
|
/* keep track of a couple codepoints for which we have no match. */
|
||||||
|
enum { nomatches_len = 64 };
|
||||||
|
static struct { long codepoint[nomatches_len]; unsigned int idx; } nomatches;
|
||||||
|
static unsigned int ellipsis_width = 0;
|
||||||
|
|
||||||
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
if (!drw || (render && (!drw->scheme || !w)) || !text || !drw->fonts)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!render) {
|
if (!render) {
|
||||||
w = ~w;
|
w = invert ? invert : ~invert;
|
||||||
} else {
|
} else {
|
||||||
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
@ -282,8 +271,10 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
}
|
}
|
||||||
|
|
||||||
usedfont = drw->fonts;
|
usedfont = drw->fonts;
|
||||||
|
if (!ellipsis_width && render)
|
||||||
|
ellipsis_width = drw_fontset_getwidth(drw, "...");
|
||||||
while (1) {
|
while (1) {
|
||||||
utf8strlen = 0;
|
ew = ellipsis_len = utf8strlen = 0;
|
||||||
utf8str = text;
|
utf8str = text;
|
||||||
nextfont = NULL;
|
nextfont = NULL;
|
||||||
while (*text) {
|
while (*text) {
|
||||||
@ -291,9 +282,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||||
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||||
if (charexists) {
|
if (charexists) {
|
||||||
if (curfont == usedfont) {
|
drw_font_getexts(curfont, text, utf8charlen, &tmpw, NULL);
|
||||||
|
if (ew + ellipsis_width <= w) {
|
||||||
|
/* keep track where the ellipsis still fits */
|
||||||
|
ellipsis_x = x + ew;
|
||||||
|
ellipsis_w = w - ew;
|
||||||
|
ellipsis_len = utf8strlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ew + tmpw > w) {
|
||||||
|
overflow = 1;
|
||||||
|
/* called from drw_fontset_getwidth_clamp():
|
||||||
|
* it wants the width AFTER the overflow
|
||||||
|
*/
|
||||||
|
if (!render)
|
||||||
|
x += tmpw;
|
||||||
|
else
|
||||||
|
utf8strlen = ellipsis_len;
|
||||||
|
} else if (curfont == usedfont) {
|
||||||
utf8strlen += utf8charlen;
|
utf8strlen += utf8charlen;
|
||||||
text += utf8charlen;
|
text += utf8charlen;
|
||||||
|
ew += tmpw;
|
||||||
} else {
|
} else {
|
||||||
nextfont = curfont;
|
nextfont = curfont;
|
||||||
}
|
}
|
||||||
@ -301,36 +310,25 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!charexists || nextfont)
|
if (overflow || !charexists || nextfont)
|
||||||
break;
|
break;
|
||||||
else
|
else
|
||||||
charexists = 0;
|
charexists = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (utf8strlen) {
|
if (utf8strlen) {
|
||||||
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
if (render) {
|
||||||
/* shorten text if necessary */
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||||
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||||
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
usedfont->xfont, x, ty, (XftChar8 *)utf8str, utf8strlen);
|
||||||
|
|
||||||
if (len) {
|
|
||||||
memcpy(buf, utf8str, len);
|
|
||||||
buf[len] = '\0';
|
|
||||||
if (len < utf8strlen)
|
|
||||||
for (i = len; i && i > len - 3; buf[--i] = '.')
|
|
||||||
; /* NOP */
|
|
||||||
|
|
||||||
if (render) {
|
|
||||||
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
|
||||||
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
|
||||||
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
|
||||||
}
|
|
||||||
x += ew;
|
|
||||||
w -= ew;
|
|
||||||
}
|
}
|
||||||
|
x += ew;
|
||||||
|
w -= ew;
|
||||||
}
|
}
|
||||||
|
if (render && overflow)
|
||||||
|
drw_text(drw, ellipsis_x, y, ellipsis_w, h, 0, "...", invert);
|
||||||
|
|
||||||
if (!*text) {
|
if (!*text || overflow) {
|
||||||
break;
|
break;
|
||||||
} else if (nextfont) {
|
} else if (nextfont) {
|
||||||
charexists = 0;
|
charexists = 0;
|
||||||
@ -340,6 +338,12 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
* character must be drawn. */
|
* character must be drawn. */
|
||||||
charexists = 1;
|
charexists = 1;
|
||||||
|
|
||||||
|
for (i = 0; i < nomatches_len; ++i) {
|
||||||
|
/* avoid calling XftFontMatch if we know we won't find a match */
|
||||||
|
if (utf8codepoint == nomatches.codepoint[i])
|
||||||
|
goto no_match;
|
||||||
|
}
|
||||||
|
|
||||||
fccharset = FcCharSetCreate();
|
fccharset = FcCharSetCreate();
|
||||||
FcCharSetAddChar(fccharset, utf8codepoint);
|
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||||
|
|
||||||
@ -351,7 +355,6 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||||
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||||
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
|
||||||
|
|
||||||
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||||
FcDefaultSubstitute(fcpattern);
|
FcDefaultSubstitute(fcpattern);
|
||||||
@ -368,6 +371,8 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
|||||||
curfont->next = usedfont;
|
curfont->next = usedfont;
|
||||||
} else {
|
} else {
|
||||||
xfont_free(usedfont);
|
xfont_free(usedfont);
|
||||||
|
nomatches.codepoint[++nomatches.idx % nomatches_len] = utf8codepoint;
|
||||||
|
no_match:
|
||||||
usedfont = drw->fonts;
|
usedfont = drw->fonts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,6 +402,15 @@ drw_fontset_getwidth(Drw *drw, const char *text)
|
|||||||
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n)
|
||||||
|
{
|
||||||
|
unsigned int tmp = 0;
|
||||||
|
if (drw && drw->fonts && text && n)
|
||||||
|
tmp = drw_text(drw, 0, 0, 0, 0, 0, text, n);
|
||||||
|
return MIN(n, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||||
{
|
{
|
||||||
|
1
drw.h
1
drw.h
@ -35,6 +35,7 @@ void drw_free(Drw *drw);
|
|||||||
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
|
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
|
||||||
void drw_fontset_free(Fnt* set);
|
void drw_fontset_free(Fnt* set);
|
||||||
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||||
|
unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int n);
|
||||||
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
||||||
/* Colorscheme abstraction */
|
/* Colorscheme abstraction */
|
||||||
|
File diff suppressed because it is too large
Load Diff
548
dwm-msg.c
548
dwm-msg.c
@ -1,548 +0,0 @@
|
|||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <yajl/yajl_gen.h>
|
|
||||||
|
|
||||||
#define IPC_MAGIC "DWM-IPC"
|
|
||||||
// clang-format off
|
|
||||||
#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C' }
|
|
||||||
// clang-format on
|
|
||||||
#define IPC_MAGIC_LEN 7 // Not including null char
|
|
||||||
|
|
||||||
#define IPC_EVENT_TAG_CHANGE "tag_change_event"
|
|
||||||
#define IPC_EVENT_CLIENT_FOCUS_CHANGE "client_focus_change_event"
|
|
||||||
#define IPC_EVENT_LAYOUT_CHANGE "layout_change_event"
|
|
||||||
#define IPC_EVENT_MONITOR_FOCUS_CHANGE "monitor_focus_change_event"
|
|
||||||
#define IPC_EVENT_FOCUSED_TITLE_CHANGE "focused_title_change_event"
|
|
||||||
#define IPC_EVENT_FOCUSED_STATE_CHANGE "focused_state_change_event"
|
|
||||||
|
|
||||||
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
|
|
||||||
#define YINT(num) yajl_gen_integer(gen, num)
|
|
||||||
#define YDOUBLE(num) yajl_gen_double(gen, num)
|
|
||||||
#define YBOOL(v) yajl_gen_bool(gen, v)
|
|
||||||
#define YNULL() yajl_gen_null(gen)
|
|
||||||
#define YARR(body) \
|
|
||||||
{ \
|
|
||||||
yajl_gen_array_open(gen); \
|
|
||||||
body; \
|
|
||||||
yajl_gen_array_close(gen); \
|
|
||||||
}
|
|
||||||
#define YMAP(body) \
|
|
||||||
{ \
|
|
||||||
yajl_gen_map_open(gen); \
|
|
||||||
body; \
|
|
||||||
yajl_gen_map_close(gen); \
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef unsigned long Window;
|
|
||||||
|
|
||||||
const char *DEFAULT_SOCKET_PATH = "/tmp/dwm.sock";
|
|
||||||
static int sock_fd = -1;
|
|
||||||
static unsigned int ignore_reply = 0;
|
|
||||||
|
|
||||||
typedef enum IPCMessageType {
|
|
||||||
IPC_TYPE_RUN_COMMAND = 0,
|
|
||||||
IPC_TYPE_GET_MONITORS = 1,
|
|
||||||
IPC_TYPE_GET_TAGS = 2,
|
|
||||||
IPC_TYPE_GET_LAYOUTS = 3,
|
|
||||||
IPC_TYPE_GET_DWM_CLIENT = 4,
|
|
||||||
IPC_TYPE_SUBSCRIBE = 5,
|
|
||||||
IPC_TYPE_EVENT = 6
|
|
||||||
} IPCMessageType;
|
|
||||||
|
|
||||||
// Every IPC message must begin with this
|
|
||||||
typedef struct dwm_ipc_header {
|
|
||||||
uint8_t magic[IPC_MAGIC_LEN];
|
|
||||||
uint32_t size;
|
|
||||||
uint8_t type;
|
|
||||||
} __attribute((packed)) dwm_ipc_header_t;
|
|
||||||
|
|
||||||
static int
|
|
||||||
recv_message(uint8_t *msg_type, uint32_t *reply_size, uint8_t **reply)
|
|
||||||
{
|
|
||||||
uint32_t read_bytes = 0;
|
|
||||||
const int32_t to_read = sizeof(dwm_ipc_header_t);
|
|
||||||
char header[to_read];
|
|
||||||
char *walk = header;
|
|
||||||
|
|
||||||
// Try to read header
|
|
||||||
while (read_bytes < to_read) {
|
|
||||||
ssize_t n = read(sock_fd, header + read_bytes, to_read - read_bytes);
|
|
||||||
|
|
||||||
if (n == 0) {
|
|
||||||
if (read_bytes == 0) {
|
|
||||||
fprintf(stderr, "Unexpectedly reached EOF while reading header.");
|
|
||||||
fprintf(stderr,
|
|
||||||
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
|
|
||||||
read_bytes, to_read);
|
|
||||||
return -2;
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Unexpectedly reached EOF while reading header.");
|
|
||||||
fprintf(stderr,
|
|
||||||
"Read %" PRIu32 " bytes, expected %" PRIu32 " total bytes.\n",
|
|
||||||
read_bytes, to_read);
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
} else if (n == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_bytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if magic string in header matches
|
|
||||||
if (memcmp(walk, IPC_MAGIC, IPC_MAGIC_LEN) != 0) {
|
|
||||||
fprintf(stderr, "Invalid magic string. Got '%.*s', expected '%s'\n",
|
|
||||||
IPC_MAGIC_LEN, walk, IPC_MAGIC);
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
walk += IPC_MAGIC_LEN;
|
|
||||||
|
|
||||||
// Extract reply size
|
|
||||||
memcpy(reply_size, walk, sizeof(uint32_t));
|
|
||||||
walk += sizeof(uint32_t);
|
|
||||||
|
|
||||||
// Extract message type
|
|
||||||
memcpy(msg_type, walk, sizeof(uint8_t));
|
|
||||||
walk += sizeof(uint8_t);
|
|
||||||
|
|
||||||
(*reply) = malloc(*reply_size);
|
|
||||||
|
|
||||||
// Extract payload
|
|
||||||
read_bytes = 0;
|
|
||||||
while (read_bytes < *reply_size) {
|
|
||||||
ssize_t n = read(sock_fd, *reply + read_bytes, *reply_size - read_bytes);
|
|
||||||
|
|
||||||
if (n == 0) {
|
|
||||||
fprintf(stderr, "Unexpectedly reached EOF while reading payload.");
|
|
||||||
fprintf(stderr, "Read %" PRIu32 " bytes, expected %" PRIu32 " bytes.\n",
|
|
||||||
read_bytes, *reply_size);
|
|
||||||
free(*reply);
|
|
||||||
return -2;
|
|
||||||
} else if (n == -1) {
|
|
||||||
if (errno == EINTR || errno == EAGAIN) continue;
|
|
||||||
free(*reply);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
read_bytes += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
read_socket(IPCMessageType *msg_type, uint32_t *msg_size, char **msg)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
|
|
||||||
while (ret != 0) {
|
|
||||||
ret = recv_message((uint8_t *)msg_type, msg_size, (uint8_t **)msg);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
|
||||||
// Try again (non-fatal error)
|
|
||||||
if (ret == -1 && (errno == EINTR || errno == EAGAIN)) continue;
|
|
||||||
|
|
||||||
fprintf(stderr, "Error receiving response from socket. ");
|
|
||||||
fprintf(stderr, "The connection might have been lost.\n");
|
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t
|
|
||||||
write_socket(const void *buf, size_t count)
|
|
||||||
{
|
|
||||||
size_t written = 0;
|
|
||||||
|
|
||||||
while (written < count) {
|
|
||||||
const ssize_t n =
|
|
||||||
write(sock_fd, ((uint8_t *)buf) + written, count - written);
|
|
||||||
|
|
||||||
if (n == -1) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
written += n;
|
|
||||||
}
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
connect_to_socket()
|
|
||||||
{
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
|
|
||||||
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
|
|
||||||
// Initialize struct to 0
|
|
||||||
memset(&addr, 0, sizeof(struct sockaddr_un));
|
|
||||||
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strcpy(addr.sun_path, DEFAULT_SOCKET_PATH);
|
|
||||||
|
|
||||||
connect(sock, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un));
|
|
||||||
|
|
||||||
sock_fd = sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
send_message(IPCMessageType msg_type, uint32_t msg_size, uint8_t *msg)
|
|
||||||
{
|
|
||||||
dwm_ipc_header_t header = {
|
|
||||||
.magic = IPC_MAGIC_ARR, .size = msg_size, .type = msg_type};
|
|
||||||
|
|
||||||
size_t header_size = sizeof(dwm_ipc_header_t);
|
|
||||||
size_t total_size = header_size + msg_size;
|
|
||||||
|
|
||||||
uint8_t buffer[total_size];
|
|
||||||
|
|
||||||
// Copy header to buffer
|
|
||||||
memcpy(buffer, &header, header_size);
|
|
||||||
// Copy message to buffer
|
|
||||||
memcpy(buffer + header_size, msg, header.size);
|
|
||||||
|
|
||||||
write_socket(buffer, total_size);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
is_float(const char *s)
|
|
||||||
{
|
|
||||||
size_t len = strlen(s);
|
|
||||||
int is_dot_used = 0;
|
|
||||||
int is_minus_used = 0;
|
|
||||||
|
|
||||||
// Floats can only have one decimal point in between or digits
|
|
||||||
// Optionally, floats can also be below zero (negative)
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (isdigit(s[i]))
|
|
||||||
continue;
|
|
||||||
else if (!is_dot_used && s[i] == '.' && i != 0 && i != len - 1) {
|
|
||||||
is_dot_used = 1;
|
|
||||||
continue;
|
|
||||||
} else if (!is_minus_used && s[i] == '-' && i == 0) {
|
|
||||||
is_minus_used = 1;
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
is_unsigned_int(const char *s)
|
|
||||||
{
|
|
||||||
size_t len = strlen(s);
|
|
||||||
|
|
||||||
// Unsigned int can only have digits
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (isdigit(s[i]))
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
is_signed_int(const char *s)
|
|
||||||
{
|
|
||||||
size_t len = strlen(s);
|
|
||||||
|
|
||||||
// Signed int can only have digits and a negative sign at the start
|
|
||||||
for (int i = 0; i < len; i++) {
|
|
||||||
if (isdigit(s[i]))
|
|
||||||
continue;
|
|
||||||
else if (i == 0 && s[i] == '-') {
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
flush_socket_reply()
|
|
||||||
{
|
|
||||||
IPCMessageType reply_type;
|
|
||||||
uint32_t reply_size;
|
|
||||||
char *reply;
|
|
||||||
|
|
||||||
read_socket(&reply_type, &reply_size, &reply);
|
|
||||||
|
|
||||||
free(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_socket_reply()
|
|
||||||
{
|
|
||||||
IPCMessageType reply_type;
|
|
||||||
uint32_t reply_size;
|
|
||||||
char *reply;
|
|
||||||
|
|
||||||
read_socket(&reply_type, &reply_size, &reply);
|
|
||||||
|
|
||||||
printf("%.*s\n", reply_size, reply);
|
|
||||||
fflush(stdout);
|
|
||||||
free(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
run_command(const char *name, char *args[], int argc)
|
|
||||||
{
|
|
||||||
const unsigned char *msg;
|
|
||||||
size_t msg_size;
|
|
||||||
|
|
||||||
yajl_gen gen = yajl_gen_alloc(NULL);
|
|
||||||
|
|
||||||
// Message format:
|
|
||||||
// {
|
|
||||||
// "command": "<name>",
|
|
||||||
// "args": [ ... ]
|
|
||||||
// }
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("command"); YSTR(name);
|
|
||||||
YSTR("args"); YARR(
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
if (is_signed_int(args[i])) {
|
|
||||||
long long num = atoll(args[i]);
|
|
||||||
YINT(num);
|
|
||||||
} else if (is_float(args[i])) {
|
|
||||||
float num = atof(args[i]);
|
|
||||||
YDOUBLE(num);
|
|
||||||
} else {
|
|
||||||
YSTR(args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
yajl_gen_get_buf(gen, &msg, &msg_size);
|
|
||||||
|
|
||||||
send_message(IPC_TYPE_RUN_COMMAND, msg_size, (uint8_t *)msg);
|
|
||||||
|
|
||||||
if (!ignore_reply)
|
|
||||||
print_socket_reply();
|
|
||||||
else
|
|
||||||
flush_socket_reply();
|
|
||||||
|
|
||||||
yajl_gen_free(gen);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_monitors()
|
|
||||||
{
|
|
||||||
send_message(IPC_TYPE_GET_MONITORS, 1, (uint8_t *)"");
|
|
||||||
print_socket_reply();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_tags()
|
|
||||||
{
|
|
||||||
send_message(IPC_TYPE_GET_TAGS, 1, (uint8_t *)"");
|
|
||||||
print_socket_reply();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_layouts()
|
|
||||||
{
|
|
||||||
send_message(IPC_TYPE_GET_LAYOUTS, 1, (uint8_t *)"");
|
|
||||||
print_socket_reply();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
get_dwm_client(Window win)
|
|
||||||
{
|
|
||||||
const unsigned char *msg;
|
|
||||||
size_t msg_size;
|
|
||||||
|
|
||||||
yajl_gen gen = yajl_gen_alloc(NULL);
|
|
||||||
|
|
||||||
// Message format:
|
|
||||||
// {
|
|
||||||
// "client_window_id": "<win>"
|
|
||||||
// }
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("client_window_id"); YINT(win);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
yajl_gen_get_buf(gen, &msg, &msg_size);
|
|
||||||
|
|
||||||
send_message(IPC_TYPE_GET_DWM_CLIENT, msg_size, (uint8_t *)msg);
|
|
||||||
|
|
||||||
print_socket_reply();
|
|
||||||
|
|
||||||
yajl_gen_free(gen);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
subscribe(const char *event)
|
|
||||||
{
|
|
||||||
const unsigned char *msg;
|
|
||||||
size_t msg_size;
|
|
||||||
|
|
||||||
yajl_gen gen = yajl_gen_alloc(NULL);
|
|
||||||
|
|
||||||
// Message format:
|
|
||||||
// {
|
|
||||||
// "event": "<event>",
|
|
||||||
// "action": "subscribe"
|
|
||||||
// }
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("event"); YSTR(event);
|
|
||||||
YSTR("action"); YSTR("subscribe");
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
yajl_gen_get_buf(gen, &msg, &msg_size);
|
|
||||||
|
|
||||||
send_message(IPC_TYPE_SUBSCRIBE, msg_size, (uint8_t *)msg);
|
|
||||||
|
|
||||||
if (!ignore_reply)
|
|
||||||
print_socket_reply();
|
|
||||||
else
|
|
||||||
flush_socket_reply();
|
|
||||||
|
|
||||||
yajl_gen_free(gen);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
usage_error(const char *prog_name, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
|
|
||||||
fprintf(stderr, "Error: ");
|
|
||||||
vfprintf(stderr, format, args);
|
|
||||||
fprintf(stderr, "\nusage: %s <command> [...]\n", prog_name);
|
|
||||||
fprintf(stderr, "Try '%s help'\n", prog_name);
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
print_usage(const char *name)
|
|
||||||
{
|
|
||||||
printf("usage: %s [options] <command> [...]\n", name);
|
|
||||||
puts("");
|
|
||||||
puts("Commands:");
|
|
||||||
puts(" run_command <name> [args...] Run an IPC command");
|
|
||||||
puts("");
|
|
||||||
puts(" get_monitors Get monitor properties");
|
|
||||||
puts("");
|
|
||||||
puts(" get_tags Get list of tags");
|
|
||||||
puts("");
|
|
||||||
puts(" get_layouts Get list of layouts");
|
|
||||||
puts("");
|
|
||||||
puts(" get_dwm_client <window_id> Get dwm client proprties");
|
|
||||||
puts("");
|
|
||||||
puts(" subscribe [events...] Subscribe to specified events");
|
|
||||||
puts(" Options: " IPC_EVENT_TAG_CHANGE ",");
|
|
||||||
puts(" " IPC_EVENT_LAYOUT_CHANGE ",");
|
|
||||||
puts(" " IPC_EVENT_CLIENT_FOCUS_CHANGE ",");
|
|
||||||
puts(" " IPC_EVENT_MONITOR_FOCUS_CHANGE ",");
|
|
||||||
puts(" " IPC_EVENT_FOCUSED_TITLE_CHANGE ",");
|
|
||||||
puts(" " IPC_EVENT_FOCUSED_STATE_CHANGE);
|
|
||||||
puts("");
|
|
||||||
puts(" help Display this message");
|
|
||||||
puts("");
|
|
||||||
puts("Options:");
|
|
||||||
puts(" --ignore-reply Don't print reply messages from");
|
|
||||||
puts(" run_command and subscribe.");
|
|
||||||
puts("");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
const char *prog_name = argv[0];
|
|
||||||
|
|
||||||
connect_to_socket();
|
|
||||||
if (sock_fd == -1) {
|
|
||||||
fprintf(stderr, "Failed to connect to socket\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 1;
|
|
||||||
if (i < argc && strcmp(argv[i], "--ignore-reply") == 0) {
|
|
||||||
ignore_reply = 1;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i >= argc) usage_error(prog_name, "Expected an argument, got none");
|
|
||||||
|
|
||||||
if (strcmp(argv[i], "help") == 0)
|
|
||||||
print_usage(prog_name);
|
|
||||||
else if (strcmp(argv[i], "run_command") == 0) {
|
|
||||||
if (++i >= argc) usage_error(prog_name, "No command specified");
|
|
||||||
// Command name
|
|
||||||
char *command = argv[i];
|
|
||||||
// Command arguments are everything after command name
|
|
||||||
char **command_args = argv + ++i;
|
|
||||||
// Number of command arguments
|
|
||||||
int command_argc = argc - i;
|
|
||||||
run_command(command, command_args, command_argc);
|
|
||||||
} else if (strcmp(argv[i], "get_monitors") == 0) {
|
|
||||||
get_monitors();
|
|
||||||
} else if (strcmp(argv[i], "get_tags") == 0) {
|
|
||||||
get_tags();
|
|
||||||
} else if (strcmp(argv[i], "get_layouts") == 0) {
|
|
||||||
get_layouts();
|
|
||||||
} else if (strcmp(argv[i], "get_dwm_client") == 0) {
|
|
||||||
if (++i < argc) {
|
|
||||||
if (is_unsigned_int(argv[i])) {
|
|
||||||
Window win = atol(argv[i]);
|
|
||||||
get_dwm_client(win);
|
|
||||||
} else
|
|
||||||
usage_error(prog_name, "Expected unsigned integer argument");
|
|
||||||
} else
|
|
||||||
usage_error(prog_name, "Expected the window id");
|
|
||||||
} else if (strcmp(argv[i], "subscribe") == 0) {
|
|
||||||
if (++i < argc) {
|
|
||||||
for (int j = i; j < argc; j++) subscribe(argv[j]);
|
|
||||||
} else
|
|
||||||
usage_error(prog_name, "Expected event name");
|
|
||||||
// Keep listening for events forever
|
|
||||||
while (1) {
|
|
||||||
print_socket_reply();
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
usage_error(prog_name, "Invalid argument '%s'", argv[i]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
280
dwm.c
280
dwm.c
@ -30,7 +30,6 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/epoll.h>
|
|
||||||
#include <X11/cursorfont.h>
|
#include <X11/cursorfont.h>
|
||||||
#include <X11/keysym.h>
|
#include <X11/keysym.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
@ -68,21 +67,9 @@ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms *
|
|||||||
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
||||||
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
|
||||||
|
|
||||||
typedef struct TagState TagState;
|
|
||||||
struct TagState {
|
|
||||||
int selected;
|
|
||||||
int occupied;
|
|
||||||
int urgent;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ClientState ClientState;
|
|
||||||
struct ClientState {
|
|
||||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
long i;
|
int i;
|
||||||
unsigned long ui;
|
unsigned int ui;
|
||||||
float f;
|
float f;
|
||||||
const void *v;
|
const void *v;
|
||||||
} Arg;
|
} Arg;
|
||||||
@ -102,7 +89,7 @@ struct Client {
|
|||||||
float mina, maxa;
|
float mina, maxa;
|
||||||
int x, y, w, h;
|
int x, y, w, h;
|
||||||
int oldx, oldy, oldw, oldh;
|
int oldx, oldy, oldw, oldh;
|
||||||
int basew, baseh, incw, inch, maxw, maxh, minw, minh;
|
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
|
||||||
int bw, oldbw;
|
int bw, oldbw;
|
||||||
unsigned int tags;
|
unsigned int tags;
|
||||||
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
|
||||||
@ -110,7 +97,6 @@ struct Client {
|
|||||||
Client *snext;
|
Client *snext;
|
||||||
Monitor *mon;
|
Monitor *mon;
|
||||||
Window win;
|
Window win;
|
||||||
ClientState prevstate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -125,10 +111,8 @@ typedef struct {
|
|||||||
void (*arrange)(Monitor *);
|
void (*arrange)(Monitor *);
|
||||||
} Layout;
|
} Layout;
|
||||||
|
|
||||||
|
|
||||||
struct Monitor {
|
struct Monitor {
|
||||||
char ltsymbol[16];
|
char ltsymbol[16];
|
||||||
char lastltsymbol[16];
|
|
||||||
float mfact;
|
float mfact;
|
||||||
int nmaster;
|
int nmaster;
|
||||||
int num;
|
int num;
|
||||||
@ -138,17 +122,14 @@ struct Monitor {
|
|||||||
unsigned int seltags;
|
unsigned int seltags;
|
||||||
unsigned int sellt;
|
unsigned int sellt;
|
||||||
unsigned int tagset[2];
|
unsigned int tagset[2];
|
||||||
TagState tagstate;
|
|
||||||
int showbar;
|
int showbar;
|
||||||
int topbar;
|
int topbar;
|
||||||
Client *clients;
|
Client *clients;
|
||||||
Client *sel;
|
Client *sel;
|
||||||
Client *lastsel;
|
|
||||||
Client *stack;
|
Client *stack;
|
||||||
Monitor *next;
|
Monitor *next;
|
||||||
Window barwin;
|
Window barwin;
|
||||||
const Layout *lt[2];
|
const Layout *lt[2];
|
||||||
const Layout *lastlt;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -194,7 +175,6 @@ static long getstate(Window w);
|
|||||||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
|
||||||
static void grabbuttons(Client *c, int focused);
|
static void grabbuttons(Client *c, int focused);
|
||||||
static void grabkeys(void);
|
static void grabkeys(void);
|
||||||
static int handlexevent(struct epoll_event *ev);
|
|
||||||
static void incnmaster(const Arg *arg);
|
static void incnmaster(const Arg *arg);
|
||||||
static void keypress(XEvent *e);
|
static void keypress(XEvent *e);
|
||||||
static void killclient(const Arg *arg);
|
static void killclient(const Arg *arg);
|
||||||
@ -205,7 +185,7 @@ static void monocle(Monitor *m);
|
|||||||
static void motionnotify(XEvent *e);
|
static void motionnotify(XEvent *e);
|
||||||
static void movemouse(const Arg *arg);
|
static void movemouse(const Arg *arg);
|
||||||
static Client *nexttiled(Client *c);
|
static Client *nexttiled(Client *c);
|
||||||
static void pop(Client *);
|
static void pop(Client *c);
|
||||||
static void propertynotify(XEvent *e);
|
static void propertynotify(XEvent *e);
|
||||||
static void quit(const Arg *arg);
|
static void quit(const Arg *arg);
|
||||||
static Monitor *recttomon(int x, int y, int w, int h);
|
static Monitor *recttomon(int x, int y, int w, int h);
|
||||||
@ -221,17 +201,15 @@ static void setclientstate(Client *c, long state);
|
|||||||
static void setfocus(Client *c);
|
static void setfocus(Client *c);
|
||||||
static void setfullscreen(Client *c, int fullscreen);
|
static void setfullscreen(Client *c, int fullscreen);
|
||||||
static void setlayout(const Arg *arg);
|
static void setlayout(const Arg *arg);
|
||||||
static void setlayoutsafe(const Arg *arg);
|
|
||||||
static void setmfact(const Arg *arg);
|
static void setmfact(const Arg *arg);
|
||||||
static void setup(void);
|
static void setup(void);
|
||||||
static void setupepoll(void);
|
|
||||||
static void seturgent(Client *c, int urg);
|
static void seturgent(Client *c, int urg);
|
||||||
static void showhide(Client *c);
|
static void showhide(Client *c);
|
||||||
static void sigchld(int unused);
|
static void sigchld(int unused);
|
||||||
static void spawn(const Arg *arg);
|
static void spawn(const Arg *arg);
|
||||||
static void tag(const Arg *arg);
|
static void tag(const Arg *arg);
|
||||||
static void tagmon(const Arg *arg);
|
static void tagmon(const Arg *arg);
|
||||||
static void tile(Monitor *);
|
static void tile(Monitor *m);
|
||||||
static void togglebar(const Arg *arg);
|
static void togglebar(const Arg *arg);
|
||||||
static void togglefloating(const Arg *arg);
|
static void togglefloating(const Arg *arg);
|
||||||
static void toggletag(const Arg *arg);
|
static void toggletag(const Arg *arg);
|
||||||
@ -262,7 +240,7 @@ static const char broken[] = "broken";
|
|||||||
static char stext[256];
|
static char stext[256];
|
||||||
static int screen;
|
static int screen;
|
||||||
static int sw, sh; /* X display screen geometry width, height */
|
static int sw, sh; /* X display screen geometry width, height */
|
||||||
static int bh, blw = 0; /* bar geometry */
|
static int bh; /* bar height */
|
||||||
static int lrpad; /* sum of left and right padding for text */
|
static int lrpad; /* sum of left and right padding for text */
|
||||||
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
static int (*xerrorxlib)(Display *, XErrorEvent *);
|
||||||
static unsigned int numlockmask = 0;
|
static unsigned int numlockmask = 0;
|
||||||
@ -283,27 +261,17 @@ static void (*handler[LASTEvent]) (XEvent *) = {
|
|||||||
[UnmapNotify] = unmapnotify
|
[UnmapNotify] = unmapnotify
|
||||||
};
|
};
|
||||||
static Atom wmatom[WMLast], netatom[NetLast];
|
static Atom wmatom[WMLast], netatom[NetLast];
|
||||||
static int epoll_fd;
|
|
||||||
static int dpy_fd;
|
|
||||||
static int running = 1;
|
static int running = 1;
|
||||||
static Cur *cursor[CurLast];
|
static Cur *cursor[CurLast];
|
||||||
static Clr **scheme;
|
static Clr **scheme;
|
||||||
static Display *dpy;
|
static Display *dpy;
|
||||||
static Drw *drw;
|
static Drw *drw;
|
||||||
static Monitor *mons, *selmon, *lastselmon;
|
static Monitor *mons, *selmon;
|
||||||
static Window root, wmcheckwin;
|
static Window root, wmcheckwin;
|
||||||
|
|
||||||
#include "ipc.h"
|
|
||||||
|
|
||||||
/* configuration, allows nested code to access above variables */
|
/* configuration, allows nested code to access above variables */
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#ifdef VERSION
|
|
||||||
#include "IPCClient.c"
|
|
||||||
#include "yajl_dumps.c"
|
|
||||||
#include "ipc.c"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* compile-time check if all tags fit into an unsigned int bit array. */
|
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||||
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||||
|
|
||||||
@ -377,6 +345,8 @@ applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact)
|
|||||||
if (*w < bh)
|
if (*w < bh)
|
||||||
*w = bh;
|
*w = bh;
|
||||||
if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
if (resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
|
||||||
|
if (!c->hintsvalid)
|
||||||
|
updatesizehints(c);
|
||||||
/* see last two sentences in ICCCM 4.1.2.3 */
|
/* see last two sentences in ICCCM 4.1.2.3 */
|
||||||
baseismin = c->basew == c->minw && c->baseh == c->minh;
|
baseismin = c->basew == c->minw && c->baseh == c->minh;
|
||||||
if (!baseismin) { /* temporarily remove base dimensions */
|
if (!baseismin) { /* temporarily remove base dimensions */
|
||||||
@ -470,7 +440,7 @@ buttonpress(XEvent *e)
|
|||||||
if (i < LENGTH(tags)) {
|
if (i < LENGTH(tags)) {
|
||||||
click = ClkTagBar;
|
click = ClkTagBar;
|
||||||
arg.ui = 1 << i;
|
arg.ui = 1 << i;
|
||||||
} else if (ev->x < x + blw)
|
} else if (ev->x < x + TEXTW(selmon->ltsymbol))
|
||||||
click = ClkLtSymbol;
|
click = ClkLtSymbol;
|
||||||
else if (ev->x > selmon->ww - (int)TEXTW(stext))
|
else if (ev->x > selmon->ww - (int)TEXTW(stext))
|
||||||
click = ClkStatusText;
|
click = ClkStatusText;
|
||||||
@ -519,17 +489,12 @@ cleanup(void)
|
|||||||
drw_cur_free(drw, cursor[i]);
|
drw_cur_free(drw, cursor[i]);
|
||||||
for (i = 0; i < LENGTH(colors); i++)
|
for (i = 0; i < LENGTH(colors); i++)
|
||||||
free(scheme[i]);
|
free(scheme[i]);
|
||||||
|
free(scheme);
|
||||||
XDestroyWindow(dpy, wmcheckwin);
|
XDestroyWindow(dpy, wmcheckwin);
|
||||||
drw_free(drw);
|
drw_free(drw);
|
||||||
XSync(dpy, False);
|
XSync(dpy, False);
|
||||||
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
|
||||||
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
|
||||||
|
|
||||||
ipc_cleanup();
|
|
||||||
|
|
||||||
if (close(epoll_fd) < 0) {
|
|
||||||
fprintf(stderr, "Failed to close epoll file descriptor\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -766,7 +731,7 @@ drawbar(Monitor *m)
|
|||||||
urg & 1 << i);
|
urg & 1 << i);
|
||||||
x += w;
|
x += w;
|
||||||
}
|
}
|
||||||
w = blw = TEXTW(m->ltsymbol);
|
w = TEXTW(m->ltsymbol);
|
||||||
drw_setscheme(drw, scheme[SchemeNorm]);
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
|
||||||
|
|
||||||
@ -953,13 +918,11 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size)
|
|||||||
text[0] = '\0';
|
text[0] = '\0';
|
||||||
if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
|
if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
|
||||||
return 0;
|
return 0;
|
||||||
if (name.encoding == XA_STRING)
|
if (name.encoding == XA_STRING) {
|
||||||
strncpy(text, (char *)name.value, size - 1);
|
strncpy(text, (char *)name.value, size - 1);
|
||||||
else {
|
} else if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
|
||||||
if (XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
|
strncpy(text, *list, size - 1);
|
||||||
strncpy(text, *list, size - 1);
|
XFreeStringList(list);
|
||||||
XFreeStringList(list);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
text[size - 1] = '\0';
|
text[size - 1] = '\0';
|
||||||
XFree(name.value);
|
XFree(name.value);
|
||||||
@ -1005,25 +968,6 @@ grabkeys(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
handlexevent(struct epoll_event *ev)
|
|
||||||
{
|
|
||||||
if (ev->events & EPOLLIN) {
|
|
||||||
XEvent ev;
|
|
||||||
while (running && XPending(dpy)) {
|
|
||||||
XNextEvent(dpy, &ev);
|
|
||||||
if (handler[ev.type]) {
|
|
||||||
handler[ev.type](&ev); /* call handler */
|
|
||||||
ipc_send_events(mons, &lastselmon, selmon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ev-> events & EPOLLHUP) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
incnmaster(const Arg *arg)
|
incnmaster(const Arg *arg)
|
||||||
{
|
{
|
||||||
@ -1100,14 +1044,12 @@ manage(Window w, XWindowAttributes *wa)
|
|||||||
applyrules(c);
|
applyrules(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
|
if (c->x + WIDTH(c) > c->mon->wx + c->mon->ww)
|
||||||
c->x = c->mon->mx + c->mon->mw - WIDTH(c);
|
c->x = c->mon->wx + c->mon->ww - WIDTH(c);
|
||||||
if (c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
|
if (c->y + HEIGHT(c) > c->mon->wy + c->mon->wh)
|
||||||
c->y = c->mon->my + c->mon->mh - HEIGHT(c);
|
c->y = c->mon->wy + c->mon->wh - HEIGHT(c);
|
||||||
c->x = MAX(c->x, c->mon->mx);
|
c->x = MAX(c->x, c->mon->wx);
|
||||||
/* only fix client y-offset, if the client center might cover the bar */
|
c->y = MAX(c->y, c->mon->wy);
|
||||||
c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
|
|
||||||
&& (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
|
|
||||||
c->bw = borderpx;
|
c->bw = borderpx;
|
||||||
|
|
||||||
wc.border_width = c->bw;
|
wc.border_width = c->bw;
|
||||||
@ -1153,9 +1095,7 @@ maprequest(XEvent *e)
|
|||||||
static XWindowAttributes wa;
|
static XWindowAttributes wa;
|
||||||
XMapRequestEvent *ev = &e->xmaprequest;
|
XMapRequestEvent *ev = &e->xmaprequest;
|
||||||
|
|
||||||
if (!XGetWindowAttributes(dpy, ev->window, &wa))
|
if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
|
||||||
return;
|
|
||||||
if (wa.override_redirect)
|
|
||||||
return;
|
return;
|
||||||
if (!wintoclient(ev->window))
|
if (!wintoclient(ev->window))
|
||||||
manage(ev->window, &wa);
|
manage(ev->window, &wa);
|
||||||
@ -1289,7 +1229,7 @@ propertynotify(XEvent *e)
|
|||||||
arrange(c->mon);
|
arrange(c->mon);
|
||||||
break;
|
break;
|
||||||
case XA_WM_NORMAL_HINTS:
|
case XA_WM_NORMAL_HINTS:
|
||||||
updatesizehints(c);
|
c->hintsvalid = 0;
|
||||||
break;
|
break;
|
||||||
case XA_WM_HINTS:
|
case XA_WM_HINTS:
|
||||||
updatewmhints(c);
|
updatewmhints(c);
|
||||||
@ -1433,40 +1373,12 @@ restack(Monitor *m)
|
|||||||
void
|
void
|
||||||
run(void)
|
run(void)
|
||||||
{
|
{
|
||||||
int event_count = 0;
|
XEvent ev;
|
||||||
const int MAX_EVENTS = 10;
|
|
||||||
struct epoll_event events[MAX_EVENTS];
|
|
||||||
|
|
||||||
XSync(dpy, False);
|
|
||||||
|
|
||||||
/* main event loop */
|
/* main event loop */
|
||||||
while (running) {
|
XSync(dpy, False);
|
||||||
event_count = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
|
while (running && !XNextEvent(dpy, &ev))
|
||||||
|
if (handler[ev.type])
|
||||||
for (int i = 0; i < event_count; i++) {
|
handler[ev.type](&ev); /* call handler */
|
||||||
int event_fd = events[i].data.fd;
|
|
||||||
DEBUG("Got event from fd %d\n", event_fd);
|
|
||||||
|
|
||||||
if (event_fd == dpy_fd) {
|
|
||||||
// -1 means EPOLLHUP
|
|
||||||
if (handlexevent(events + i) == -1)
|
|
||||||
return;
|
|
||||||
} else if (event_fd == ipc_get_sock_fd()) {
|
|
||||||
ipc_handle_socket_epoll_event(events + i);
|
|
||||||
} else if (ipc_is_client_registered(event_fd)){
|
|
||||||
if (ipc_handle_client_epoll_event(events + i, mons, &lastselmon, selmon,
|
|
||||||
tags, LENGTH(tags), layouts, LENGTH(layouts)) < 0) {
|
|
||||||
fprintf(stderr, "Error handling IPC event on fd %d\n", event_fd);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Got event from unknown fd %d, ptr %p, u32 %d, u64 %lu",
|
|
||||||
event_fd, events[i].data.ptr, events[i].data.u32,
|
|
||||||
events[i].data.u64);
|
|
||||||
fprintf(stderr, " with events %d\n", events[i].events);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1600,18 +1512,6 @@ setlayout(const Arg *arg)
|
|||||||
drawbar(selmon);
|
drawbar(selmon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
setlayoutsafe(const Arg *arg)
|
|
||||||
{
|
|
||||||
const Layout *ltptr = (Layout *)arg->v;
|
|
||||||
if (ltptr == 0)
|
|
||||||
setlayout(arg);
|
|
||||||
for (int i = 0; i < LENGTH(layouts); i++) {
|
|
||||||
if (ltptr == &layouts[i])
|
|
||||||
setlayout(arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* arg > 1.0 will set mfact absolutely */
|
/* arg > 1.0 will set mfact absolutely */
|
||||||
void
|
void
|
||||||
setmfact(const Arg *arg)
|
setmfact(const Arg *arg)
|
||||||
@ -1695,36 +1595,6 @@ setup(void)
|
|||||||
XSelectInput(dpy, root, wa.event_mask);
|
XSelectInput(dpy, root, wa.event_mask);
|
||||||
grabkeys();
|
grabkeys();
|
||||||
focus(NULL);
|
focus(NULL);
|
||||||
setupepoll();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
setupepoll(void)
|
|
||||||
{
|
|
||||||
epoll_fd = epoll_create1(0);
|
|
||||||
dpy_fd = ConnectionNumber(dpy);
|
|
||||||
struct epoll_event dpy_event;
|
|
||||||
|
|
||||||
// Initialize struct to 0
|
|
||||||
memset(&dpy_event, 0, sizeof(dpy_event));
|
|
||||||
|
|
||||||
DEBUG("Display socket is fd %d\n", dpy_fd);
|
|
||||||
|
|
||||||
if (epoll_fd == -1) {
|
|
||||||
fputs("Failed to create epoll file descriptor", stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
dpy_event.events = EPOLLIN;
|
|
||||||
dpy_event.data.fd = dpy_fd;
|
|
||||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, dpy_fd, &dpy_event)) {
|
|
||||||
fputs("Failed to add display file descriptor to epoll", stderr);
|
|
||||||
close(epoll_fd);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ipc_init(ipcsockpath, epoll_fd, ipccommands, LENGTH(ipccommands)) < 0) {
|
|
||||||
fputs("Failed to initialize IPC\n", stderr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1769,16 +1639,12 @@ sigchld(int unused)
|
|||||||
void
|
void
|
||||||
spawn(const Arg *arg)
|
spawn(const Arg *arg)
|
||||||
{
|
{
|
||||||
if (arg->v == dmenucmd)
|
|
||||||
dmenumon[0] = '0' + selmon->num;
|
|
||||||
if (fork() == 0) {
|
if (fork() == 0) {
|
||||||
if (dpy)
|
if (dpy)
|
||||||
close(ConnectionNumber(dpy));
|
close(ConnectionNumber(dpy));
|
||||||
setsid();
|
setsid();
|
||||||
execvp(((char **)arg->v)[0], (char **)arg->v);
|
execvp(((char **)arg->v)[0], (char **)arg->v);
|
||||||
fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
|
die("dwm: execvp '%s' failed:", ((char **)arg->v)[0]);
|
||||||
perror(" failed");
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1903,6 +1769,7 @@ unmanage(Client *c, int destroyed)
|
|||||||
wc.border_width = c->oldbw;
|
wc.border_width = c->oldbw;
|
||||||
XGrabServer(dpy); /* avoid race conditions */
|
XGrabServer(dpy); /* avoid race conditions */
|
||||||
XSetErrorHandler(xerrordummy);
|
XSetErrorHandler(xerrordummy);
|
||||||
|
XSelectInput(dpy, c->win, NoEventMask);
|
||||||
XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
|
XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
|
||||||
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
|
XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
|
||||||
setclientstate(c, WithdrawnState);
|
setclientstate(c, WithdrawnState);
|
||||||
@ -2000,42 +1867,42 @@ updategeom(void)
|
|||||||
memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
|
memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
|
||||||
XFree(info);
|
XFree(info);
|
||||||
nn = j;
|
nn = j;
|
||||||
if (n <= nn) { /* new monitors available */
|
|
||||||
for (i = 0; i < (nn - n); i++) {
|
/* new monitors if nn > n */
|
||||||
for (m = mons; m && m->next; m = m->next);
|
for (i = n; i < nn; i++) {
|
||||||
if (m)
|
for (m = mons; m && m->next; m = m->next);
|
||||||
m->next = createmon();
|
if (m)
|
||||||
else
|
m->next = createmon();
|
||||||
mons = createmon();
|
else
|
||||||
|
mons = createmon();
|
||||||
|
}
|
||||||
|
for (i = 0, m = mons; i < nn && m; m = m->next, i++)
|
||||||
|
if (i >= n
|
||||||
|
|| unique[i].x_org != m->mx || unique[i].y_org != m->my
|
||||||
|
|| unique[i].width != m->mw || unique[i].height != m->mh)
|
||||||
|
{
|
||||||
|
dirty = 1;
|
||||||
|
m->num = i;
|
||||||
|
m->mx = m->wx = unique[i].x_org;
|
||||||
|
m->my = m->wy = unique[i].y_org;
|
||||||
|
m->mw = m->ww = unique[i].width;
|
||||||
|
m->mh = m->wh = unique[i].height;
|
||||||
|
updatebarpos(m);
|
||||||
}
|
}
|
||||||
for (i = 0, m = mons; i < nn && m; m = m->next, i++)
|
/* removed monitors if n > nn */
|
||||||
if (i >= n
|
for (i = nn; i < n; i++) {
|
||||||
|| unique[i].x_org != m->mx || unique[i].y_org != m->my
|
for (m = mons; m && m->next; m = m->next);
|
||||||
|| unique[i].width != m->mw || unique[i].height != m->mh)
|
while ((c = m->clients)) {
|
||||||
{
|
dirty = 1;
|
||||||
dirty = 1;
|
m->clients = c->next;
|
||||||
m->num = i;
|
detachstack(c);
|
||||||
m->mx = m->wx = unique[i].x_org;
|
c->mon = mons;
|
||||||
m->my = m->wy = unique[i].y_org;
|
attach(c);
|
||||||
m->mw = m->ww = unique[i].width;
|
attachstack(c);
|
||||||
m->mh = m->wh = unique[i].height;
|
|
||||||
updatebarpos(m);
|
|
||||||
}
|
|
||||||
} else { /* less monitors available nn < n */
|
|
||||||
for (i = nn; i < n; i++) {
|
|
||||||
for (m = mons; m && m->next; m = m->next);
|
|
||||||
while ((c = m->clients)) {
|
|
||||||
dirty = 1;
|
|
||||||
m->clients = c->next;
|
|
||||||
detachstack(c);
|
|
||||||
c->mon = mons;
|
|
||||||
attach(c);
|
|
||||||
attachstack(c);
|
|
||||||
}
|
|
||||||
if (m == selmon)
|
|
||||||
selmon = mons;
|
|
||||||
cleanupmon(m);
|
|
||||||
}
|
}
|
||||||
|
if (m == selmon)
|
||||||
|
selmon = mons;
|
||||||
|
cleanupmon(m);
|
||||||
}
|
}
|
||||||
free(unique);
|
free(unique);
|
||||||
} else
|
} else
|
||||||
@ -2114,6 +1981,7 @@ updatesizehints(Client *c)
|
|||||||
} else
|
} else
|
||||||
c->maxa = c->mina = 0.0;
|
c->maxa = c->mina = 0.0;
|
||||||
c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
|
c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
|
||||||
|
c->hintsvalid = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2127,18 +1995,10 @@ updatestatus(void)
|
|||||||
void
|
void
|
||||||
updatetitle(Client *c)
|
updatetitle(Client *c)
|
||||||
{
|
{
|
||||||
char oldname[sizeof(c->name)];
|
|
||||||
strcpy(oldname, c->name);
|
|
||||||
|
|
||||||
if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
|
if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
|
||||||
gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
|
gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
|
||||||
if (c->name[0] == '\0') /* hack to mark broken clients */
|
if (c->name[0] == '\0') /* hack to mark broken clients */
|
||||||
strcpy(c->name, broken);
|
strcpy(c->name, broken);
|
||||||
|
|
||||||
for (Monitor *m = mons; m; m = m->next) {
|
|
||||||
if (m->sel == c && strcmp(oldname, c->name) != 0)
|
|
||||||
ipc_focused_title_change_event(m->num, c->win, oldname, c->name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2255,12 +2115,10 @@ zoom(const Arg *arg)
|
|||||||
{
|
{
|
||||||
Client *c = selmon->sel;
|
Client *c = selmon->sel;
|
||||||
|
|
||||||
if (!selmon->lt[selmon->sellt]->arrange
|
if (!selmon->lt[selmon->sellt]->arrange || !c || c->isfloating)
|
||||||
|| (selmon->sel && selmon->sel->isfloating))
|
return;
|
||||||
|
if (c == nexttiled(selmon->clients) && !(c = nexttiled(c->next)))
|
||||||
return;
|
return;
|
||||||
if (c == nexttiled(selmon->clients))
|
|
||||||
if (!c || !(c = nexttiled(c->next)))
|
|
||||||
return;
|
|
||||||
pop(c);
|
pop(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
320
ipc.h
320
ipc.h
@ -1,320 +0,0 @@
|
|||||||
#ifndef IPC_H_
|
|
||||||
#define IPC_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
#include <yajl/yajl_gen.h>
|
|
||||||
|
|
||||||
#include "IPCClient.h"
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
#define IPC_MAGIC "DWM-IPC"
|
|
||||||
#define IPC_MAGIC_ARR { 'D', 'W', 'M', '-', 'I', 'P', 'C'}
|
|
||||||
#define IPC_MAGIC_LEN 7 // Not including null char
|
|
||||||
|
|
||||||
#define IPCCOMMAND(FUNC, ARGC, TYPES) \
|
|
||||||
{ #FUNC, {FUNC }, ARGC, (ArgType[ARGC])TYPES }
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
typedef enum IPCMessageType {
|
|
||||||
IPC_TYPE_RUN_COMMAND = 0,
|
|
||||||
IPC_TYPE_GET_MONITORS = 1,
|
|
||||||
IPC_TYPE_GET_TAGS = 2,
|
|
||||||
IPC_TYPE_GET_LAYOUTS = 3,
|
|
||||||
IPC_TYPE_GET_DWM_CLIENT = 4,
|
|
||||||
IPC_TYPE_SUBSCRIBE = 5,
|
|
||||||
IPC_TYPE_EVENT = 6
|
|
||||||
} IPCMessageType;
|
|
||||||
|
|
||||||
typedef enum IPCEvent {
|
|
||||||
IPC_EVENT_TAG_CHANGE = 1 << 0,
|
|
||||||
IPC_EVENT_CLIENT_FOCUS_CHANGE = 1 << 1,
|
|
||||||
IPC_EVENT_LAYOUT_CHANGE = 1 << 2,
|
|
||||||
IPC_EVENT_MONITOR_FOCUS_CHANGE = 1 << 3,
|
|
||||||
IPC_EVENT_FOCUSED_TITLE_CHANGE = 1 << 4,
|
|
||||||
IPC_EVENT_FOCUSED_STATE_CHANGE = 1 << 5
|
|
||||||
} IPCEvent;
|
|
||||||
|
|
||||||
typedef enum IPCSubscriptionAction {
|
|
||||||
IPC_ACTION_UNSUBSCRIBE = 0,
|
|
||||||
IPC_ACTION_SUBSCRIBE = 1
|
|
||||||
} IPCSubscriptionAction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Every IPC packet starts with this structure
|
|
||||||
*/
|
|
||||||
typedef struct dwm_ipc_header {
|
|
||||||
uint8_t magic[IPC_MAGIC_LEN];
|
|
||||||
uint32_t size;
|
|
||||||
uint8_t type;
|
|
||||||
} __attribute((packed)) dwm_ipc_header_t;
|
|
||||||
|
|
||||||
typedef enum ArgType {
|
|
||||||
ARG_TYPE_NONE = 0,
|
|
||||||
ARG_TYPE_UINT = 1,
|
|
||||||
ARG_TYPE_SINT = 2,
|
|
||||||
ARG_TYPE_FLOAT = 3,
|
|
||||||
ARG_TYPE_PTR = 4,
|
|
||||||
ARG_TYPE_STR = 5
|
|
||||||
} ArgType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An IPCCommand function can have either of these function signatures
|
|
||||||
*/
|
|
||||||
typedef union ArgFunction {
|
|
||||||
void (*single_param)(const Arg *);
|
|
||||||
void (*array_param)(const Arg *, int);
|
|
||||||
} ArgFunction;
|
|
||||||
|
|
||||||
typedef struct IPCCommand {
|
|
||||||
char *name;
|
|
||||||
ArgFunction func;
|
|
||||||
unsigned int argc;
|
|
||||||
ArgType *arg_types;
|
|
||||||
} IPCCommand;
|
|
||||||
|
|
||||||
typedef struct IPCParsedCommand {
|
|
||||||
char *name;
|
|
||||||
Arg *args;
|
|
||||||
ArgType *arg_types;
|
|
||||||
unsigned int argc;
|
|
||||||
} IPCParsedCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the IPC socket and the IPC module
|
|
||||||
*
|
|
||||||
* @param socket_path Path to create the socket at
|
|
||||||
* @param epoll_fd File descriptor for epoll
|
|
||||||
* @param commands Address of IPCCommands array defined in config.h
|
|
||||||
* @param commands_len Length of commands[] array
|
|
||||||
*
|
|
||||||
* @return int The file descriptor of the socket if it was successfully created,
|
|
||||||
* -1 otherwise
|
|
||||||
*/
|
|
||||||
int ipc_init(const char *socket_path, const int p_epoll_fd,
|
|
||||||
IPCCommand commands[], const int commands_len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uninitialize the socket and module. Free allocated memory and restore static
|
|
||||||
* variables to their state before ipc_init
|
|
||||||
*/
|
|
||||||
void ipc_cleanup();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the file descriptor of the IPC socket
|
|
||||||
*
|
|
||||||
* @return int File descriptor of IPC socket, -1 if socket not created.
|
|
||||||
*/
|
|
||||||
int ipc_get_sock_fd();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get address to IPCClient with specified file descriptor
|
|
||||||
*
|
|
||||||
* @param fd File descriptor of IPC Client
|
|
||||||
*
|
|
||||||
* @return Address to IPCClient with specified file descriptor, -1 otherwise
|
|
||||||
*/
|
|
||||||
IPCClient *ipc_get_client(int fd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an IPC client exists with the specified file descriptor
|
|
||||||
*
|
|
||||||
* @param fd File descriptor
|
|
||||||
*
|
|
||||||
* @return int 1 if client exists, 0 otherwise
|
|
||||||
*/
|
|
||||||
int ipc_is_client_registered(int fd);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect an IPCClient from the socket and remove the client from the list
|
|
||||||
* of known connected clients
|
|
||||||
*
|
|
||||||
* @param c Address of IPCClient
|
|
||||||
*
|
|
||||||
* @return 0 if the client's file descriptor was closed successfully, the
|
|
||||||
* result of executing close() on the file descriptor otherwise.
|
|
||||||
*/
|
|
||||||
int ipc_drop_client(IPCClient *c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept an IPC Client requesting to connect to the socket and add it to the
|
|
||||||
* list of clients
|
|
||||||
*
|
|
||||||
* @return File descriptor of new client, -1 on error
|
|
||||||
*/
|
|
||||||
int ipc_accept_client();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read an incoming message from an accepted IPC client
|
|
||||||
*
|
|
||||||
* @param c Address of IPCClient
|
|
||||||
* @param msg_type Address to IPCMessageType variable which will be assigned
|
|
||||||
* the message type of the received message
|
|
||||||
* @param msg_size Address to uint32_t variable which will be assigned the size
|
|
||||||
* of the received message
|
|
||||||
* @param msg Address to char* variable which will be assigned the address of
|
|
||||||
* the received message. This must be freed using free().
|
|
||||||
*
|
|
||||||
* @return 0 on success, -1 on error reading message, -2 if reading the message
|
|
||||||
* resulted in EAGAIN, EINTR, or EWOULDBLOCK.
|
|
||||||
*/
|
|
||||||
int ipc_read_client(IPCClient *c, IPCMessageType *msg_type, uint32_t *msg_size,
|
|
||||||
char **msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write any pending buffer of the client to the client's socket
|
|
||||||
*
|
|
||||||
* @param c Client whose buffer to write
|
|
||||||
*
|
|
||||||
* @return Number of bytes written >= 0, -1 otherwise. errno will still be set
|
|
||||||
* from the write operation.
|
|
||||||
*/
|
|
||||||
ssize_t ipc_write_client(IPCClient *c);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare a message in the specified client's buffer.
|
|
||||||
*
|
|
||||||
* @param c Client to prepare message for
|
|
||||||
* @param msg_type Type of message to prepare
|
|
||||||
* @param msg_size Size of the message in bytes. Should not exceed
|
|
||||||
* MAX_MESSAGE_SIZE
|
|
||||||
* @param msg Message to prepare (not including header). This pointer can be
|
|
||||||
* freed after the function invocation.
|
|
||||||
*/
|
|
||||||
void ipc_prepare_send_message(IPCClient *c, const IPCMessageType msg_type,
|
|
||||||
const uint32_t msg_size, const char *msg);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare an error message in the specified client's buffer
|
|
||||||
*
|
|
||||||
* @param c Client to prepare message for
|
|
||||||
* @param msg_type Type of message
|
|
||||||
* @param format Format string following vsprintf
|
|
||||||
* @param ... Arguments for format string
|
|
||||||
*/
|
|
||||||
void ipc_prepare_reply_failure(IPCClient *c, IPCMessageType msg_type,
|
|
||||||
const char *format, ...);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepare a success message in the specified client's buffer
|
|
||||||
*
|
|
||||||
* @param c Client to prepare message for
|
|
||||||
* @param msg_type Type of message
|
|
||||||
*/
|
|
||||||
void ipc_prepare_reply_success(IPCClient *c, IPCMessageType msg_type);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a tag_change_event to all subscribers. Should be called only when there
|
|
||||||
* has been a tag state change.
|
|
||||||
*
|
|
||||||
* @param mon_num The index of the monitor (Monitor.num property)
|
|
||||||
* @param old_state The old tag state
|
|
||||||
* @param new_state The new (now current) tag state
|
|
||||||
*/
|
|
||||||
void ipc_tag_change_event(const int mon_num, TagState old_state,
|
|
||||||
TagState new_state);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a client_focus_change_event to all subscribers. Should be called only
|
|
||||||
* when the client focus changes.
|
|
||||||
*
|
|
||||||
* @param mon_num The index of the monitor (Monitor.num property)
|
|
||||||
* @param old_client The old DWM client selection (Monitor.oldsel)
|
|
||||||
* @param new_client The new (now current) DWM client selection
|
|
||||||
*/
|
|
||||||
void ipc_client_focus_change_event(const int mon_num, Client *old_client,
|
|
||||||
Client *new_client);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a layout_change_event to all subscribers. Should be called only
|
|
||||||
* when there has been a layout change.
|
|
||||||
*
|
|
||||||
* @param mon_num The index of the monitor (Monitor.num property)
|
|
||||||
* @param old_symbol The old layout symbol
|
|
||||||
* @param old_layout Address to the old Layout
|
|
||||||
* @param new_symbol The new (now current) layout symbol
|
|
||||||
* @param new_layout Address to the new Layout
|
|
||||||
*/
|
|
||||||
void ipc_layout_change_event(const int mon_num, const char *old_symbol,
|
|
||||||
const Layout *old_layout, const char *new_symbol,
|
|
||||||
const Layout *new_layout);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a monitor_focus_change_event to all subscribers. Should be called only
|
|
||||||
* when the monitor focus changes.
|
|
||||||
*
|
|
||||||
* @param last_mon_num The index of the previously selected monitor
|
|
||||||
* @param new_mon_num The index of the newly selected monitor
|
|
||||||
*/
|
|
||||||
void ipc_monitor_focus_change_event(const int last_mon_num,
|
|
||||||
const int new_mon_num);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a focused_title_change_event to all subscribers. Should only be called
|
|
||||||
* if a selected client has a title change.
|
|
||||||
*
|
|
||||||
* @param mon_num Index of the client's monitor
|
|
||||||
* @param client_id Window XID of client
|
|
||||||
* @param old_name Old name of the client window
|
|
||||||
* @param new_name New name of the client window
|
|
||||||
*/
|
|
||||||
void ipc_focused_title_change_event(const int mon_num, const Window client_id,
|
|
||||||
const char *old_name, const char *new_name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a focused_state_change_event to all subscribers. Should only be called
|
|
||||||
* if a selected client has a state change.
|
|
||||||
*
|
|
||||||
* @param mon_num Index of the client's monitor
|
|
||||||
* @param client_id Window XID of client
|
|
||||||
* @param old_state Old state of the client
|
|
||||||
* @param new_state New state of the client
|
|
||||||
*/
|
|
||||||
void ipc_focused_state_change_event(const int mon_num, const Window client_id,
|
|
||||||
const ClientState *old_state,
|
|
||||||
const ClientState *new_state);
|
|
||||||
/**
|
|
||||||
* Check to see if an event has occured and call the *_change_event functions
|
|
||||||
* accordingly
|
|
||||||
*
|
|
||||||
* @param mons Address of Monitor pointing to start of linked list
|
|
||||||
* @param lastselmon Address of pointer to previously selected monitor
|
|
||||||
* @param selmon Address of selected Monitor
|
|
||||||
*/
|
|
||||||
void ipc_send_events(Monitor *mons, Monitor **lastselmon, Monitor *selmon);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an epoll event caused by a registered IPC client. Read, process, and
|
|
||||||
* handle any received messages from clients. Write pending buffer to client if
|
|
||||||
* the client is ready to receive messages. Drop clients that have sent an
|
|
||||||
* EPOLLHUP.
|
|
||||||
*
|
|
||||||
* @param ev Associated epoll event returned by epoll_wait
|
|
||||||
* @param mons Address of Monitor pointing to start of linked list
|
|
||||||
* @param selmon Address of selected Monitor
|
|
||||||
* @param lastselmon Address of pointer to previously selected monitor
|
|
||||||
* @param tags Array of tag names
|
|
||||||
* @param tags_len Length of tags array
|
|
||||||
* @param layouts Array of available layouts
|
|
||||||
* @param layouts_len Length of layouts array
|
|
||||||
*
|
|
||||||
* @return 0 if event was successfully handled, -1 on any error receiving
|
|
||||||
* or handling incoming messages or unhandled epoll event.
|
|
||||||
*/
|
|
||||||
int ipc_handle_client_epoll_event(struct epoll_event *ev, Monitor *mons,
|
|
||||||
Monitor **lastselmon, Monitor *selmon,
|
|
||||||
const char *tags[], const int tags_len,
|
|
||||||
const Layout *layouts, const int layouts_len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle an epoll event caused by the IPC socket. This function only handles an
|
|
||||||
* EPOLLIN event indicating a new client requesting to connect to the socket.
|
|
||||||
*
|
|
||||||
* @param ev Associated epoll event returned by epoll_wait
|
|
||||||
*
|
|
||||||
* @return 0, if the event was successfully handled, -1 if not an EPOLLIN event
|
|
||||||
* or if a new IPC client connection request could not be accepted.
|
|
||||||
*/
|
|
||||||
int ipc_handle_socket_epoll_event(struct epoll_event *ev);
|
|
||||||
|
|
||||||
#endif /* IPC_H_ */
|
|
150
util.c
150
util.c
@ -3,23 +3,12 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
void *
|
|
||||||
ecalloc(size_t nmemb, size_t size)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
if (!(p = calloc(nmemb, size)))
|
|
||||||
die("calloc:");
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
die(const char *fmt, ...) {
|
die(const char *fmt, ...)
|
||||||
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
@ -36,135 +25,12 @@ die(const char *fmt, ...) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void *
|
||||||
normalizepath(const char *path, char **normal)
|
ecalloc(size_t nmemb, size_t size)
|
||||||
{
|
{
|
||||||
size_t len = strlen(path);
|
void *p;
|
||||||
*normal = (char *)malloc((len + 1) * sizeof(char));
|
|
||||||
const char *walk = path;
|
|
||||||
const char *match;
|
|
||||||
size_t newlen = 0;
|
|
||||||
|
|
||||||
while ((match = strchr(walk, '/'))) {
|
if (!(p = calloc(nmemb, size)))
|
||||||
// Copy everything between match and walk
|
die("calloc:");
|
||||||
strncpy(*normal + newlen, walk, match - walk);
|
return p;
|
||||||
newlen += match - walk;
|
|
||||||
walk += match - walk;
|
|
||||||
|
|
||||||
// Skip all repeating slashes
|
|
||||||
while (*walk == '/')
|
|
||||||
walk++;
|
|
||||||
|
|
||||||
// If not last character in path
|
|
||||||
if (walk != path + len)
|
|
||||||
(*normal)[newlen++] = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
(*normal)[newlen++] = '\0';
|
|
||||||
|
|
||||||
// Copy remaining path
|
|
||||||
strcat(*normal, walk);
|
|
||||||
newlen += strlen(walk);
|
|
||||||
|
|
||||||
*normal = (char *)realloc(*normal, newlen * sizeof(char));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
parentdir(const char *path, char **parent)
|
|
||||||
{
|
|
||||||
char *normal;
|
|
||||||
char *walk;
|
|
||||||
|
|
||||||
normalizepath(path, &normal);
|
|
||||||
|
|
||||||
// Pointer to last '/'
|
|
||||||
if (!(walk = strrchr(normal, '/'))) {
|
|
||||||
free(normal);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get path up to last '/'
|
|
||||||
size_t len = walk - normal;
|
|
||||||
*parent = (char *)malloc((len + 1) * sizeof(char));
|
|
||||||
|
|
||||||
// Copy path up to last '/'
|
|
||||||
strncpy(*parent, normal, len);
|
|
||||||
// Add null char
|
|
||||||
(*parent)[len] = '\0';
|
|
||||||
|
|
||||||
free(normal);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
mkdirp(const char *path)
|
|
||||||
{
|
|
||||||
char *normal;
|
|
||||||
char *walk;
|
|
||||||
size_t normallen;
|
|
||||||
|
|
||||||
normalizepath(path, &normal);
|
|
||||||
normallen = strlen(normal);
|
|
||||||
walk = normal;
|
|
||||||
|
|
||||||
while (walk < normal + normallen + 1) {
|
|
||||||
// Get length from walk to next /
|
|
||||||
size_t n = strcspn(walk, "/");
|
|
||||||
|
|
||||||
// Skip path /
|
|
||||||
if (n == 0) {
|
|
||||||
walk++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Length of current path segment
|
|
||||||
size_t curpathlen = walk - normal + n;
|
|
||||||
char curpath[curpathlen + 1];
|
|
||||||
struct stat s;
|
|
||||||
|
|
||||||
// Copy path segment to stat
|
|
||||||
strncpy(curpath, normal, curpathlen);
|
|
||||||
strcpy(curpath + curpathlen, "");
|
|
||||||
int res = stat(curpath, &s);
|
|
||||||
|
|
||||||
if (res < 0) {
|
|
||||||
if (errno == ENOENT) {
|
|
||||||
DEBUG("Making directory %s\n", curpath);
|
|
||||||
if (mkdir(curpath, 0700) < 0) {
|
|
||||||
fprintf(stderr, "Failed to make directory %s\n", curpath);
|
|
||||||
perror("");
|
|
||||||
free(normal);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "Error statting directory %s\n", curpath);
|
|
||||||
perror("");
|
|
||||||
free(normal);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue to next path segment
|
|
||||||
walk += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(normal);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
nullterminate(char **str, size_t *len)
|
|
||||||
{
|
|
||||||
if ((*str)[*len - 1] == '\0')
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
(*len)++;
|
|
||||||
*str = (char*)realloc(*str, *len * sizeof(char));
|
|
||||||
(*str)[*len - 1] = '\0';
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
10
util.h
10
util.h
@ -4,15 +4,5 @@
|
|||||||
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||||
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
|
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define DEBUG(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void die(const char *fmt, ...);
|
void die(const char *fmt, ...);
|
||||||
void *ecalloc(size_t nmemb, size_t size);
|
void *ecalloc(size_t nmemb, size_t size);
|
||||||
int normalizepath(const char *path, char **normal);
|
|
||||||
int mkdirp(const char *path);
|
|
||||||
int parentdir(const char *path, char **parent);
|
|
||||||
int nullterminate(char **str, size_t *len);
|
|
||||||
|
351
yajl_dumps.c
351
yajl_dumps.c
@ -1,351 +0,0 @@
|
|||||||
#include "yajl_dumps.h"
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_tag(yajl_gen gen, const char *name, const int tag_mask)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("bit_mask"); YINT(tag_mask);
|
|
||||||
YSTR("name"); YSTR(name);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_tags(yajl_gen gen, const char *tags[], int tags_len)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YARR(
|
|
||||||
for (int i = 0; i < tags_len; i++)
|
|
||||||
dump_tag(gen, tags[i], 1 << i);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_client(yajl_gen gen, Client *c)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("name"); YSTR(c->name);
|
|
||||||
YSTR("tags"); YINT(c->tags);
|
|
||||||
YSTR("window_id"); YINT(c->win);
|
|
||||||
YSTR("monitor_number"); YINT(c->mon->num);
|
|
||||||
|
|
||||||
YSTR("geometry"); YMAP(
|
|
||||||
YSTR("current"); YMAP (
|
|
||||||
YSTR("x"); YINT(c->x);
|
|
||||||
YSTR("y"); YINT(c->y);
|
|
||||||
YSTR("width"); YINT(c->w);
|
|
||||||
YSTR("height"); YINT(c->h);
|
|
||||||
)
|
|
||||||
YSTR("old"); YMAP(
|
|
||||||
YSTR("x"); YINT(c->oldx);
|
|
||||||
YSTR("y"); YINT(c->oldy);
|
|
||||||
YSTR("width"); YINT(c->oldw);
|
|
||||||
YSTR("height"); YINT(c->oldh);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("size_hints"); YMAP(
|
|
||||||
YSTR("base"); YMAP(
|
|
||||||
YSTR("width"); YINT(c->basew);
|
|
||||||
YSTR("height"); YINT(c->baseh);
|
|
||||||
)
|
|
||||||
YSTR("step"); YMAP(
|
|
||||||
YSTR("width"); YINT(c->incw);
|
|
||||||
YSTR("height"); YINT(c->inch);
|
|
||||||
)
|
|
||||||
YSTR("max"); YMAP(
|
|
||||||
YSTR("width"); YINT(c->maxw);
|
|
||||||
YSTR("height"); YINT(c->maxh);
|
|
||||||
)
|
|
||||||
YSTR("min"); YMAP(
|
|
||||||
YSTR("width"); YINT(c->minw);
|
|
||||||
YSTR("height"); YINT(c->minh);
|
|
||||||
)
|
|
||||||
YSTR("aspect_ratio"); YMAP(
|
|
||||||
YSTR("min"); YDOUBLE(c->mina);
|
|
||||||
YSTR("max"); YDOUBLE(c->maxa);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("border_width"); YMAP(
|
|
||||||
YSTR("current"); YINT(c->bw);
|
|
||||||
YSTR("old"); YINT(c->oldbw);
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("states"); YMAP(
|
|
||||||
YSTR("is_fixed"); YBOOL(c->isfixed);
|
|
||||||
YSTR("is_floating"); YBOOL(c->isfloating);
|
|
||||||
YSTR("is_urgent"); YBOOL(c->isurgent);
|
|
||||||
YSTR("never_focus"); YBOOL(c->neverfocus);
|
|
||||||
YSTR("old_state"); YBOOL(c->oldstate);
|
|
||||||
YSTR("is_fullscreen"); YBOOL(c->isfullscreen);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_monitor(yajl_gen gen, Monitor *mon, int is_selected)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("master_factor"); YDOUBLE(mon->mfact);
|
|
||||||
YSTR("num_master"); YINT(mon->nmaster);
|
|
||||||
YSTR("num"); YINT(mon->num);
|
|
||||||
YSTR("is_selected"); YBOOL(is_selected);
|
|
||||||
|
|
||||||
YSTR("monitor_geometry"); YMAP(
|
|
||||||
YSTR("x"); YINT(mon->mx);
|
|
||||||
YSTR("y"); YINT(mon->my);
|
|
||||||
YSTR("width"); YINT(mon->mw);
|
|
||||||
YSTR("height"); YINT(mon->mh);
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("window_geometry"); YMAP(
|
|
||||||
YSTR("x"); YINT(mon->wx);
|
|
||||||
YSTR("y"); YINT(mon->wy);
|
|
||||||
YSTR("width"); YINT(mon->ww);
|
|
||||||
YSTR("height"); YINT(mon->wh);
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("tagset"); YMAP(
|
|
||||||
YSTR("current"); YINT(mon->tagset[mon->seltags]);
|
|
||||||
YSTR("old"); YINT(mon->tagset[mon->seltags ^ 1]);
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("tag_state"); dump_tag_state(gen, mon->tagstate);
|
|
||||||
|
|
||||||
YSTR("clients"); YMAP(
|
|
||||||
YSTR("selected"); YINT(mon->sel ? mon->sel->win : 0);
|
|
||||||
YSTR("stack"); YARR(
|
|
||||||
for (Client* c = mon->stack; c; c = c->snext)
|
|
||||||
YINT(c->win);
|
|
||||||
)
|
|
||||||
YSTR("all"); YARR(
|
|
||||||
for (Client* c = mon->clients; c; c = c->next)
|
|
||||||
YINT(c->win);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("layout"); YMAP(
|
|
||||||
YSTR("symbol"); YMAP(
|
|
||||||
YSTR("current"); YSTR(mon->ltsymbol);
|
|
||||||
YSTR("old"); YSTR(mon->lastltsymbol);
|
|
||||||
)
|
|
||||||
YSTR("address"); YMAP(
|
|
||||||
YSTR("current"); YINT((uintptr_t)mon->lt[mon->sellt]);
|
|
||||||
YSTR("old"); YINT((uintptr_t)mon->lt[mon->sellt ^ 1]);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
YSTR("bar"); YMAP(
|
|
||||||
YSTR("y"); YINT(mon->by);
|
|
||||||
YSTR("is_shown"); YBOOL(mon->showbar);
|
|
||||||
YSTR("is_top"); YBOOL(mon->topbar);
|
|
||||||
YSTR("window_id"); YINT(mon->barwin);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YARR(
|
|
||||||
for (Monitor *mon = mons; mon; mon = mon->next) {
|
|
||||||
if (mon == selmon)
|
|
||||||
dump_monitor(gen, mon, 1);
|
|
||||||
else
|
|
||||||
dump_monitor(gen, mon, 0);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YARR(
|
|
||||||
for (int i = 0; i < layouts_len; i++) {
|
|
||||||
YMAP(
|
|
||||||
// Check for a NULL pointer. The cycle layouts patch adds an entry at
|
|
||||||
// the end of the layouts array with a NULL pointer for the symbol
|
|
||||||
YSTR("symbol"); YSTR((layouts[i].symbol ? layouts[i].symbol : ""));
|
|
||||||
YSTR("address"); YINT((uintptr_t)(layouts + i));
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_tag_state(yajl_gen gen, TagState state)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("selected"); YINT(state.selected);
|
|
||||||
YSTR("occupied"); YINT(state.occupied);
|
|
||||||
YSTR("urgent"); YINT(state.urgent);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_tag_event(yajl_gen gen, int mon_num, TagState old_state,
|
|
||||||
TagState new_state)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("tag_change_event"); YMAP(
|
|
||||||
YSTR("monitor_number"); YINT(mon_num);
|
|
||||||
YSTR("old_state"); dump_tag_state(gen, old_state);
|
|
||||||
YSTR("new_state"); dump_tag_state(gen, new_state);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_client_focus_change_event(yajl_gen gen, Client *old_client,
|
|
||||||
Client *new_client, int mon_num)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("client_focus_change_event"); YMAP(
|
|
||||||
YSTR("monitor_number"); YINT(mon_num);
|
|
||||||
YSTR("old_win_id"); old_client == NULL ? YNULL() : YINT(old_client->win);
|
|
||||||
YSTR("new_win_id"); new_client == NULL ? YNULL() : YINT(new_client->win);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_layout_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const char *old_symbol, const Layout *old_layout,
|
|
||||||
const char *new_symbol, const Layout *new_layout)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("layout_change_event"); YMAP(
|
|
||||||
YSTR("monitor_number"); YINT(mon_num);
|
|
||||||
YSTR("old_symbol"); YSTR(old_symbol);
|
|
||||||
YSTR("old_address"); YINT((uintptr_t)old_layout);
|
|
||||||
YSTR("new_symbol"); YSTR(new_symbol);
|
|
||||||
YSTR("new_address"); YINT((uintptr_t)new_layout);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num,
|
|
||||||
const int new_mon_num)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("monitor_focus_change_event"); YMAP(
|
|
||||||
YSTR("old_monitor_number"); YINT(last_mon_num);
|
|
||||||
YSTR("new_monitor_number"); YINT(new_mon_num);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_focused_title_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const Window client_id, const char *old_name,
|
|
||||||
const char *new_name)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("focused_title_change_event"); YMAP(
|
|
||||||
YSTR("monitor_number"); YINT(mon_num);
|
|
||||||
YSTR("client_window_id"); YINT(client_id);
|
|
||||||
YSTR("old_name"); YSTR(old_name);
|
|
||||||
YSTR("new_name"); YSTR(new_name);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_client_state(yajl_gen gen, const ClientState *state)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("old_state"); YBOOL(state->oldstate);
|
|
||||||
YSTR("is_fixed"); YBOOL(state->isfixed);
|
|
||||||
YSTR("is_floating"); YBOOL(state->isfloating);
|
|
||||||
YSTR("is_fullscreen"); YBOOL(state->isfullscreen);
|
|
||||||
YSTR("is_urgent"); YBOOL(state->isurgent);
|
|
||||||
YSTR("never_focus"); YBOOL(state->neverfocus);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_focused_state_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const Window client_id,
|
|
||||||
const ClientState *old_state,
|
|
||||||
const ClientState *new_state)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("focused_state_change_event"); YMAP(
|
|
||||||
YSTR("monitor_number"); YINT(mon_num);
|
|
||||||
YSTR("client_window_id"); YINT(client_id);
|
|
||||||
YSTR("old_state"); dump_client_state(gen, old_state);
|
|
||||||
YSTR("new_state"); dump_client_state(gen, new_state);
|
|
||||||
)
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
dump_error_message(yajl_gen gen, const char *reason)
|
|
||||||
{
|
|
||||||
// clang-format off
|
|
||||||
YMAP(
|
|
||||||
YSTR("result"); YSTR("error");
|
|
||||||
YSTR("reason"); YSTR(reason);
|
|
||||||
)
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
65
yajl_dumps.h
65
yajl_dumps.h
@ -1,65 +0,0 @@
|
|||||||
#ifndef YAJL_DUMPS_H_
|
|
||||||
#define YAJL_DUMPS_H_
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <yajl/yajl_gen.h>
|
|
||||||
|
|
||||||
#define YSTR(str) yajl_gen_string(gen, (unsigned char *)str, strlen(str))
|
|
||||||
#define YINT(num) yajl_gen_integer(gen, num)
|
|
||||||
#define YDOUBLE(num) yajl_gen_double(gen, num)
|
|
||||||
#define YBOOL(v) yajl_gen_bool(gen, v)
|
|
||||||
#define YNULL() yajl_gen_null(gen)
|
|
||||||
#define YARR(body) \
|
|
||||||
{ \
|
|
||||||
yajl_gen_array_open(gen); \
|
|
||||||
body; \
|
|
||||||
yajl_gen_array_close(gen); \
|
|
||||||
}
|
|
||||||
#define YMAP(body) \
|
|
||||||
{ \
|
|
||||||
yajl_gen_map_open(gen); \
|
|
||||||
body; \
|
|
||||||
yajl_gen_map_close(gen); \
|
|
||||||
}
|
|
||||||
|
|
||||||
int dump_tag(yajl_gen gen, const char *name, const int tag_mask);
|
|
||||||
|
|
||||||
int dump_tags(yajl_gen gen, const char *tags[], int tags_len);
|
|
||||||
|
|
||||||
int dump_client(yajl_gen gen, Client *c);
|
|
||||||
|
|
||||||
int dump_monitor(yajl_gen gen, Monitor *mon, int is_selected);
|
|
||||||
|
|
||||||
int dump_monitors(yajl_gen gen, Monitor *mons, Monitor *selmon);
|
|
||||||
|
|
||||||
int dump_layouts(yajl_gen gen, const Layout layouts[], const int layouts_len);
|
|
||||||
|
|
||||||
int dump_tag_state(yajl_gen gen, TagState state);
|
|
||||||
|
|
||||||
int dump_tag_event(yajl_gen gen, int mon_num, TagState old_state,
|
|
||||||
TagState new_state);
|
|
||||||
|
|
||||||
int dump_client_focus_change_event(yajl_gen gen, Client *old_client,
|
|
||||||
Client *new_client, int mon_num);
|
|
||||||
|
|
||||||
int dump_layout_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const char *old_symbol, const Layout *old_layout,
|
|
||||||
const char *new_symbol, const Layout *new_layout);
|
|
||||||
|
|
||||||
int dump_monitor_focus_change_event(yajl_gen gen, const int last_mon_num,
|
|
||||||
const int new_mon_num);
|
|
||||||
|
|
||||||
int dump_focused_title_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const Window client_id,
|
|
||||||
const char *old_name, const char *new_name);
|
|
||||||
|
|
||||||
int dump_client_state(yajl_gen gen, const ClientState *state);
|
|
||||||
|
|
||||||
int dump_focused_state_change_event(yajl_gen gen, const int mon_num,
|
|
||||||
const Window client_id,
|
|
||||||
const ClientState *old_state,
|
|
||||||
const ClientState *new_state);
|
|
||||||
|
|
||||||
int dump_error_message(yajl_gen gen, const char *reason);
|
|
||||||
|
|
||||||
#endif // YAJL_DUMPS_H_
|
|
Reference in New Issue
Block a user