Skip to content

Commit

Permalink
Adding support for little endian and using it as default.
Browse files Browse the repository at this point in the history
  • Loading branch information
moaxcp committed Dec 17, 2024
1 parent 14817b2 commit b12d18e
Show file tree
Hide file tree
Showing 23 changed files with 1,145 additions and 458 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ https://www.x.org/releases/X11R7.6/doc/libXtst/recordlib.html

# versions

## 0.19.0

* Added support for little-endian and made it default to match the server default.

## 0.18.2

* Fixing XAuthority when parsing number
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ plugins {
}

allprojects {
version = '0.18.2'
version = '0.19.0'
group = 'com.github.moaxcp.x11'
repositories {
mavenCentral()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ public class KeySymMain {

public static void main(String... args) throws IOException {
try (X11Client client = X11Client.connect()) {
List<Byte> keyCodes = client.keySymToKeyCodes(KeySym.XK_Escape);
for (byte keyCode : keyCodes) {
KeySym keySym = client.keyCodeToKeySym(keyCode, (short) 0);
log.info(keySym.toString());
for (var keySym : KeySym.values()) {
List<Byte> keyCodes = client.keySymToKeyCodes(keySym);
for (byte keyCode : keyCodes) {
KeySym result = client.keyCodeToKeySym(keyCode, (short) 0);
log.info(keySym + ": " + result);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public static void main(String... args) throws IOException {
while (true) {
EnableContextReply reply = data.getNextReply(enableContext.getReplyFunction());
log.info(String.format("Next reply: %s", reply));
XEvent replyData = data.readEvent(toX11Input(reply.getData()));
XEvent replyData = data.readEvent(toX11Input(data.getBigEndian(), reply.getData()));
log.info(String.format("reply data: %s", replyData));

if (replyData instanceof KeyPressEvent) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.github.moaxcp.x11.examples;

import com.github.moaxcp.x11.keysym.KeySym;
import com.github.moaxcp.x11.protocol.BigEndian;
import com.github.moaxcp.x11.protocol.LittleEndian;
import com.github.moaxcp.x11.protocol.Utilities;
import com.github.moaxcp.x11.protocol.XEvent;
import com.github.moaxcp.x11.protocol.xproto.*;
import com.github.moaxcp.x11.x11client.X11Client;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -45,13 +46,20 @@ public static void main(String... args) throws IOException {
//XSetWMProtocols for adding delete atom
InternAtomReply wmProtocols = client.send(InternAtom.builder().name(Utilities.toByteList("WM_PROTOCOLS")).build());
InternAtomReply deleteAtom = client.send(InternAtom.builder().name(Utilities.toByteList("WM_DELETE_WINDOW")).build());

List<Byte> write;
if (client.getBigEndian()) {
write = BigEndian.writeList(deleteAtom.getAtom());
} else {
write = LittleEndian.writeList(deleteAtom.getAtom());
}
client.send(ChangeProperty.builder()
.window(window.getWid())
.property(wmProtocols.getAtom())
.type(Atom.ATOM.getValue())
.format((byte) 32)
.mode(PropMode.REPLACE)
.data(Utilities.toList(ByteBuffer.allocate(4).putInt(deleteAtom.getAtom()).array()))
.data(write)
.dataLen(1)
.build());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
import com.github.moaxcp.x11.x11client.api.record.RecordApi;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.github.moaxcp.x11.protocol.Utilities.toIntegers;
import static com.github.moaxcp.x11.protocol.Utilities.toList;

/**
* An x11 client. The client handles two types of requests: {@link OneWayRequest} and {@link TwoWayRequest}.
Expand Down Expand Up @@ -50,8 +48,12 @@ public class X11Client implements AutoCloseable {
* @throws X11ClientException If connection to server could not be established
*/
public static X11Client connect(DisplayName displayName, XAuthority xAuthority) {
return connect(false, displayName, xAuthority);
}

public static X11Client connect(boolean bigEndian, DisplayName displayName, XAuthority xAuthority) {
try {
return new X11Client(X11Connection.connect(displayName, xAuthority));
return new X11Client(X11Connection.connect(bigEndian, displayName, xAuthority));
} catch (IOException e) {
throw new X11ClientException("Could not connect with " + displayName, e);
}
Expand All @@ -64,8 +66,12 @@ public static X11Client connect(DisplayName displayName, XAuthority xAuthority)
* @throws X11ClientException If connection to server could not be established
*/
public static X11Client connect() {
return connect(false);
}

public static X11Client connect(boolean bigEndian) {
try {
return new X11Client(X11Connection.connect());
return new X11Client(X11Connection.connect(bigEndian));
} catch (IOException e) {
throw new X11ClientException("Could not connect", e);
}
Expand All @@ -78,8 +84,12 @@ public static X11Client connect() {
* @throws X11ClientException If connection to server could not be established
*/
public static X11Client connect(DisplayName name) {
return connect(false, name);
}

public static X11Client connect(boolean bigEndian, DisplayName name) {
try {
return new X11Client(X11Connection.connect(name));
return new X11Client(X11Connection.connect(bigEndian, name));
} catch (IOException e) {
throw new X11ClientException("Could not connect with " + name, e);
}
Expand Down Expand Up @@ -111,6 +121,10 @@ public Setup getSetup() {
return connection.getSetup();
}

public boolean getBigEndian() {
return connection.getBigEndian();
}

/**
* Returns the default screen number.
*/
Expand Down Expand Up @@ -444,14 +458,20 @@ public List<Integer> getWMProtocols(int wid) {
}

public void setWMProtocols(int wid, int atom) {
List<Byte> bytes;
if (connection.getBigEndian()) {
bytes = BigEndian.writeList(atom);
} else {
bytes = LittleEndian.writeList(atom);
}
send(ChangeProperty.builder()
.window(wid)
.property(getAtom("WM_PROTOCOLS").getId())
.type(Atom.ATOM.getValue())
.format((byte) 32)
.mode(PropMode.REPLACE)
.dataLen(1)
.data(toList(ByteBuffer.allocate(4).putInt(atom).array()))
.data(bytes)
.build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class X11Connection implements AutoCloseable {
private final DisplayName displayName;
private final XAuthority xAuthority;
private final Setup setup;
private final boolean bigEndian;
private final Socket socket;
private final X11InputStream in;
private final X11OutputStream out;
Expand All @@ -36,14 +37,20 @@ public class X11Connection implements AutoCloseable {
* @throws NullPointerException if any parameter is null
* @throws UnsupportedOperationException if the connection code is authenticate or any other result
*/
X11Connection(DisplayName displayName, XAuthority xAuthority, Socket socket) throws IOException {
X11Connection(boolean bigEndian, DisplayName displayName, XAuthority xAuthority, Socket socket) throws IOException {
this.displayName = requireNonNull(displayName, "displayName");
this.xAuthority = requireNonNull(xAuthority, "xAuthority");
this.socket = requireNonNull(socket, "socket");
this.bigEndian = bigEndian;
//using BufferedInputStream to support mark/reset
in = new X11InputStream(new BufferedInputStream(socket.getInputStream(), 128));
out = new X11OutputStream(socket.getOutputStream());
sendConnectionSetup();
if (bigEndian) {
in = new X11BigEndianInputStream(new BufferedInputStream(socket.getInputStream(), 128));
out = new X11BigEndianOutputStream(socket.getOutputStream());
} else {
in = new X11LittleEndianInputStream(new BufferedInputStream(socket.getInputStream(), 128));
out = new X11LittleEndianOutputStream(socket.getOutputStream());
}
sendConnectionSetup(bigEndian);
in.mark(1);
byte result = in.readInt8();
in.reset();
Expand Down Expand Up @@ -74,6 +81,10 @@ public Setup getSetup() {
return this.setup;
}

public boolean getBigEndian() {
return bigEndian;
}

public X11Input getX11Input() {
return in;
}
Expand All @@ -98,9 +109,9 @@ public int getPort() {
return socket.getPort();
}

private void sendConnectionSetup() throws IOException {
private void sendConnectionSetup(boolean bigEndian) throws IOException {
SetupRequest setup = SetupRequest.builder()
.byteOrder((byte) 'B')
.byteOrder(bigEndian ? (byte) 'B' : (byte) 'l')
.protocolMajorVersion((short) 11)
.protocolMinorVersion((short) 0)
.authorizationProtocolName(xAuthority.getProtocolName())
Expand All @@ -117,7 +128,7 @@ private void sendConnectionSetup() throws IOException {
* @return
* @throws NullPointerException if displayName is null.
*/
public static X11Connection connect(DisplayName displayName, XAuthority xAuthority) throws IOException {
public static X11Connection connect(boolean bigEndian, DisplayName displayName, XAuthority xAuthority) throws IOException {
requireNonNull(xAuthority, "xAuthority");
Socket socket;

Expand All @@ -129,26 +140,26 @@ public static X11Connection connect(DisplayName displayName, XAuthority xAuthori
socket = new Socket(address, displayName.getPort());
}

return new X11Connection(displayName, xAuthority, socket);
return new X11Connection(bigEndian, displayName, xAuthority, socket);
}

public static X11Connection connect() throws IOException {
public static X11Connection connect(boolean bigEndian) throws IOException {
DisplayName name = DisplayName.standard();
List<XAuthority> authorities = XAuthority.getAuthorities(XAuthority.getXAuthorityFile());
Optional<XAuthority> authority = XAuthority.getAuthority(authorities, name);
if (!authority.isPresent()) {
throw new IllegalStateException("could not find authority for environment");
}
return connect(name, authority.get());
return connect(bigEndian, name, authority.get());
}

public static X11Connection connect(DisplayName name) throws IOException {
public static X11Connection connect(boolean bigEndian, DisplayName name) throws IOException {
List<XAuthority> authorities = XAuthority.getAuthorities(XAuthority.getXAuthorityFile());
Optional<XAuthority> authority = XAuthority.getAuthority(authorities, name);
if (!authority.isPresent()) {
throw new IllegalStateException("could not find authority for environment");
}
return connect(name, authority.get());
return connect(bigEndian, name, authority.get());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public RecordDataParser(X11Client client, EnableContextReply reply, ReplySequenc
this.client = client;
this.reply = reply;
this.tracker = tracker;
data = toX11Input(reply.getData());
data = toX11Input(client.getBigEndian(), reply.getData());
}

public RecordReply parse() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,31 @@ public class X11ConnectionTest {

@Test
void constructor_fails_on_null_displayName() {
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(null, xAuthority, socket));
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(false, null, xAuthority, socket));
assertThat(exception).hasMessage("displayName");
}

@Test
void constructor_fails_on_null_xAuthority() {
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(new DisplayName(":0"), null, socket));
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(false, new DisplayName(":0"), null, socket));
assertThat(exception).hasMessage("xAuthority");
}

@Test
void constructor_fails_on_null_socket() {
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(new DisplayName(":0"), xAuthority, null));
NullPointerException exception = assertThrows(NullPointerException.class, () -> new X11Connection(false, new DisplayName(":0"), xAuthority, null));
assertThat(exception).hasMessage("socket");
}

@Test
void connect_fails_on_null_displayName() {
NullPointerException exception = assertThrows(NullPointerException.class, () -> X11Connection.connect(null, xAuthority));
NullPointerException exception = assertThrows(NullPointerException.class, () -> X11Connection.connect(false, null, xAuthority));
assertThat(exception).hasMessage("Cannot invoke \"com.github.moaxcp.x11.protocol.DisplayName.isForUnixSocket()\" because \"displayName\" is null");
}

@Test
void connect_fails_on_null_xAuthority() {
NullPointerException exception = assertThrows(NullPointerException.class, () -> X11Connection.connect(new DisplayName((":0")), null));
NullPointerException exception = assertThrows(NullPointerException.class, () -> X11Connection.connect(false, new DisplayName((":0")), null));
assertThat(exception).hasMessage("xAuthority");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.github.moaxcp.x11.protocol;

import lombok.experimental.UtilityClass;

import java.util.Arrays;
import java.util.List;

@UtilityClass
public class BigEndian {
public static byte[] write(int value, byte[] bytes) {
bytes[0] = (byte) (value >> 24);
bytes[1] = (byte) (value >> 16);
bytes[2] = (byte) (value >> 8);
bytes[3] = (byte) value;
return bytes;
}

public static List<Byte> writeList(int value) {
return Arrays.asList((byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value);
}
}
Loading

0 comments on commit b12d18e

Please sign in to comment.