Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
edadma committed Sep 12, 2021
1 parent f277475 commit c3449b2
Show file tree
Hide file tree
Showing 7 changed files with 328 additions and 27 deletions.
161 changes: 159 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,159 @@
-sn-template
============
cairo-xlib
==========

![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/edadma/cairo-xlib?include_prereleases) ![GitHub (Pre-)Release Date](https://img.shields.io/github/release-date-pre/edadma/cairo-xlib) ![GitHub last commit](https://img.shields.io/github/last-commit/edadma/cairo-xlib) ![GitHub](https://img.shields.io/github/license/edadma/cairo-xlib)

*cairo-xlib* provides Scala Native bindings for the [Cairo](https://www.cairographics.org/) 2D graphics library [X Window System](https://www.x.org/releases/current/) rendering using [XLib](https://www.x.org/releases/current/doc/libX11/libX11/libX11.html).

Overview
--------

The goal of this project is to provide an easy-to-use Scala Native bindings for the Cairo 2D graphics library XLib Surfaces support. Currently, the great majority of XLib related Cairo functions are supported. Also, the `cairo_xlib.XlibSurface` class extends `libcairo.Surface` so that this library is perfectly interoperable with `libcairo`. By using this library as a dependency, you also get Scala Native bindings for XLib. The XLib bindings are not complete, but work is ongoing.

The more "programmer friendly" part of this library is found in the `io.github.edadma.cairo_xlib` package. That's the only
package you need to import from, as seen in the example below. The other package in the library
is `io.github.edadma.cairo_xlib.extern` which provides for interaction with the *cairo_xlib* C library using Scala Native
interoperability elements from the so-call `unsafe` namespace. There are no public declarations in
the `io.github.edadma.cairo_xlib` package that use `unsafe` types in their parameter or return types, making it a pure
Scala bindings library. Consequently, you never have to worry about memory allocation or type conversions.

Usage
-----

To use this library, `libcairo2` (and `libx11`) needs to be installed:

```shell
sudo apt install libcairo2
```

Include the following in your `project/plugins.sbt`:

```sbt
addSbtPlugin("com.codecommit" % "sbt-github-packages" % "0.5.2")

```

Include the following in your `build.sbt`:

```sbt
resolvers += Resolver.githubPackages("edadma")

libraryDependencies += "io.github.edadma" %%% "cairo-xlib" % "0.1.0"

```

Use the following `import` in your code:

```scala
import io.github.edadma.cairo_xlib._

```

Example
--------

This example creates a Window with a simple drawing in it. However, this example also prints all keyboard, mouse and window redraw events, showing how to check for and interpret various X11 events.

```scala
import io.github.edadma.cairo_xlib._
import io.github.edadma.libcairo._
import io.github.edadma.xlib._

object Main extends App {

val sfc = createX11Surface(500, 500)

eventLoop(sfc)
destroyX11Surface(sfc)

def createX11Surface(width: Int, height: Int): XlibSurface = {
val dsp: Display = openDisplay(null)

if (dsp.isNull) {
Console.err.println("can't open display")
sys.exit(1)
}

val screen = dsp.defaultScreen
val da = dsp.createSimpleWindow(dsp.defaultRootWindow, 0, 0, width, height, 0, 0, 0)

dsp.selectInput(
da,
ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask)
dsp.mapWindow(da)

val sfc = surfaceCreate(dsp, da, dsp.defaultVisual(screen), width, height)

sfc.setSize(width, height)
sfc
}

def eventLoop(sfc: XlibSurface): Unit = {
val event = new Event

while (sfc.getDisplay.nextEvent(event) == Success) {
event.getType match {
case `ButtonPress` =>
println(s"button press: ${event.button.button}, ${event.button.x}, ${event.button.y}, ${event.button.time}")
case `ButtonRelease` => println(s"button release: ${event.button.button}")
case `MotionNotify` => println(s"motion: ${event.motion.state}, ${event.motion.x}, ${event.motion.y}")
case `KeyPress` =>
val (keystr, keysym) = event.key.lookupString
val keysymstr = keysymToString(keysym)

println(s"key press: $keystr, $keysym, $keysymstr")

if (keysym == XK_Return) {
event.destroy()
return
}
case `KeyRelease` =>
val (keystr, keysym) = event.key.lookupString
val keysymstr = keysymToString(keysym)

println(s"key release: $keystr, $keysym, $keysymstr")
case `Expose` =>
println("redraw")
drawX11Surface(sfc)
case e => println(e)
}
}

event.destroy()
}

def drawX11Surface(sfc: Surface): Unit = {
val ctx = sfc.create

ctx.setSourceRGB(.5, .5, .5)
ctx.paint()
ctx.moveTo(20, 20)
ctx.lineTo(200, 400)
ctx.lineTo(450, 100)
ctx.lineTo(20, 20)
ctx.setSourceRGB(0, 1, 0)
ctx.fill()
ctx.destroy()
}

def destroyX11Surface(sfc: XlibSurface): Unit = {
val dsp: Display = openDisplay(null)

sfc.destroy()
dsp.closeDisplay
}

}

```

Documentation
-------------

API documentation is forthcoming, however documentation for Cairo XLib Surfaces is
found [here](https://www.cairographics.org/manual/cairo-XLib-Surfaces.html), and for the current release of XLib [here](https://www.x.org/releases/current/doc/libX11/libX11/libX11.html).

License
-------

[ISC](https://github.com/edadma/cairo_xlib/blob/main/LICENSE)
10 changes: 8 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name := "-sn-template"
name := "cairo-xlib"

version := "0.1.0"

Expand Down Expand Up @@ -31,7 +31,7 @@ resolvers += "Typesafe Repository" at "https://repo.typesafe.com/typesafe/releas

resolvers += Resolver.githubPackages("edadma")

Compile / mainClass := Some(s"${organization.value}.${name.value.replace('-', '_')}.Main")
Compile / mainClass := Some("Main")

licenses := Seq("ISC" -> url("https://opensource.org/licenses/ISC"))

Expand All @@ -43,6 +43,12 @@ homepage := Some(url("https://github.com/edadma/" + name.value))
// "com.github.scopt" %%% "scopt" % "4.0.1"
//)

libraryDependencies ++=
Seq(
"io.github.edadma" %%% "libcairo" % "0.1.4",
"io.github.edadma" %%% "xlib" % "0.1.0.pre.18"
)

publishMavenStyle := true

Test / publishArtifact := false
Expand Down
89 changes: 89 additions & 0 deletions src/main/scala/Main.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//import io.github.edadma.cairo_xlib._
//import io.github.edadma.libcairo._
//import io.github.edadma.xlib._
//
//object Main extends App {
//
// val sfc = createX11Surface(500, 500)
//
// eventLoop(sfc)
// destroyX11Surface(sfc)
//
// def createX11Surface(width: Int, height: Int): XlibSurface = {
// val dsp: Display = openDisplay(null)
//
// if (dsp.isNull) {
// Console.err.println("can't open display")
// sys.exit(1)
// }
//
// val screen = dsp.defaultScreen
// val da = dsp.createSimpleWindow(dsp.defaultRootWindow, 0, 0, width, height, 0, 0, 0)
//
// dsp.selectInput(
// da,
// ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask)
// dsp.mapWindow(da)
//
// val sfc = surfaceCreate(dsp, da, dsp.defaultVisual(screen), width, height)
//
// sfc.setSize(width, height)
// sfc
// }
//
// def eventLoop(sfc: XlibSurface): Unit = {
// val event = new Event
//
// while (sfc.getDisplay.nextEvent(event) == Success) {
// event.getType match {
// case `ButtonPress` =>
// println(s"button press: ${event.button.button}, ${event.button.x}, ${event.button.y}, ${event.button.time}")
// case `ButtonRelease` => println(s"button release: ${event.button.button}")
// case `MotionNotify` => println(s"motion: ${event.motion.state}, ${event.motion.x}, ${event.motion.y}")
// case `KeyPress` =>
// val (keystr, keysym) = event.key.lookupString
// val keysymstr = keysymToString(keysym)
//
// println(s"key press: $keystr, $keysym, $keysymstr")
//
// if (keysym == XK_Return) {
// event.destroy()
// return
// }
// case `KeyRelease` =>
// val (keystr, keysym) = event.key.lookupString
// val keysymstr = keysymToString(keysym)
//
// println(s"key release: $keystr, $keysym, $keysymstr")
// case `Expose` =>
// println("redraw")
// drawX11Surface(sfc)
// case e => println(e)
// }
// }
//
// event.destroy()
// }
//
// def drawX11Surface(sfc: Surface): Unit = {
// val ctx = sfc.create
//
// ctx.setSourceRGB(.5, .5, .5)
// ctx.paint()
// ctx.moveTo(20, 20)
// ctx.lineTo(200, 400)
// ctx.lineTo(450, 100)
// ctx.lineTo(20, 20)
// ctx.setSourceRGB(0, 1, 0)
// ctx.fill()
// ctx.destroy()
// }
//
// def destroyX11Surface(sfc: XlibSurface): Unit = {
// val dsp: Display = openDisplay(null)
//
// sfc.destroy()
// dsp.closeDisplay
// }
//
//}
7 changes: 0 additions & 7 deletions src/main/scala/io/github/edadma/_sn_template/Main.scala

This file was deleted.

33 changes: 33 additions & 0 deletions src/main/scala/io/github/edadma/cairo_xlib/extern/CairoXlib.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github.edadma.cairo_xlib.extern

import io.github.edadma.libcairo.extern.LibCairo._
import io.github.edadma.xlib.extern.Xlib._

import scala.scalanative.unsafe._

@link("cairo")
@extern
object CairoXlib {

def cairo_xlib_surface_create(dpy: Display,
drawable: Drawable,
visual: Visual,
width: CInt,
height: CInt): cairo_surface_tp = extern //49
def cairo_xlib_surface_create_for_bitmap(dpy: Display,
bitmap: Pixmap,
screen: Screen,
width: CInt,
height: CInt): cairo_surface_tp = extern //56
def cairo_xlib_surface_set_size(surface: cairo_surface_tp, width: CInt, height: CInt): Unit = extern //63
def cairo_xlib_surface_set_drawable(surface: cairo_surface_tp, drawable: Drawable, width: CInt, height: CInt): Unit =
extern //68
def cairo_xlib_surface_get_display(surface: cairo_surface_tp): Display = extern //74
def cairo_xlib_surface_get_drawable(surface: cairo_surface_tp): Drawable = extern //77
def cairo_xlib_surface_get_screen(surface: cairo_surface_tp): Screen = extern //80
def cairo_xlib_surface_get_visual(surface: cairo_surface_tp): Visual = extern //83
def cairo_xlib_surface_get_depth(surface: cairo_surface_tp): CInt = extern //86
def cairo_xlib_surface_get_width(surface: cairo_surface_tp): CInt = extern //89
def cairo_xlib_surface_get_height(surface: cairo_surface_tp): CInt = extern //92

}
39 changes: 39 additions & 0 deletions src/main/scala/io/github/edadma/cairo_xlib/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package io.github.edadma

import io.github.edadma.libcairo._
import io.github.edadma.libcairo.extern.LibCairo.cairo_surface_tp
import io.github.edadma.xlib._
import io.github.edadma.cairo_xlib.extern.{CairoXlib => lib}

package object cairo_xlib {

implicit class XlibSurface(override val surface: cairo_surface_tp) extends Surface(surface) {

def setSize(width: Int, height: Int): Unit = lib.cairo_xlib_surface_set_size(surface, width, height)

def setDrawable(drawable: Drawable, width: Int, height: Int): Unit =
lib.cairo_xlib_surface_set_drawable(surface, drawable, width, height)

def getDisplay: Display = lib.cairo_xlib_surface_get_display(surface)

def getDrawable: Drawable = lib.cairo_xlib_surface_get_drawable(surface)

def getScreen: Screen = lib.cairo_xlib_surface_get_screen(surface)

def getVisual: Visual = lib.cairo_xlib_surface_get_visual(surface)

def getDepth: Int = lib.cairo_xlib_surface_get_depth(surface)

def getWidth: Int = lib.cairo_xlib_surface_get_width(surface)

def getHeight: Int = lib.cairo_xlib_surface_get_height(surface)

}

def surfaceCreate(dpy: Display, drawable: Drawable, visual: Visual, width: Int, height: Int): XlibSurface =
lib.cairo_xlib_surface_create(dpy.ptr, drawable, visual.visual, width, height)

def surfaceCreateForBitmap(dpy: Display, bitmap: Pixmap, screen: Screen, width: Int, height: Int): cairo_surface_tp =
lib.cairo_xlib_surface_create_for_bitmap(dpy.ptr, bitmap, screen, width, height)

}
16 changes: 0 additions & 16 deletions src/test/scala/io/github/edadma/_sn_template/Tests.scala

This file was deleted.

0 comments on commit c3449b2

Please sign in to comment.