Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backports to 1.x #198

Draft
wants to merge 11 commits into
base: libmypaint-v1
Choose a base branch
from
37 changes: 37 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Test

on:
- push
- pull_request

jobs:
linux:
name: Linux
runs-on: ubuntu-22.04
strategy:
matrix:
configureFlags:
- ""
- "--with-introspection"
- "--with-gegl"
include:
- configureFlags: "--with-introspection"
extraDeps: "libgirepository1.0-dev"
- configureFlags: "--with-gegl"
extraDeps: "libgegl-dev"
steps:
- uses: actions/checkout@v4
- name: "Install dependencies"
run: |
sudo apt-get update
sudo apt-get install -y \
libjson-c-dev \
intltool \
${{ matrix.extraDeps }}
- name: "Build"
run: |
./autogen.sh
./configure ${{ matrix.configureFlags }}
make
- name: "Run tests"
run: make distcheck
32 changes: 0 additions & 32 deletions .travis.yml

This file was deleted.

48 changes: 31 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,31 +30,45 @@ License: ISC, see [COPYING](./COPYING) for details.
On recent Debian-like systems, you can type the following
to get started with a standard configuration:

$ sudo apt install -y build-essential
$ sudo apt install -y libjson-c-dev libgirepository1.0-dev libglib2.0-dev
# apt install -y build-essential
# apt install -y libjson-c-dev libgirepository1.0-dev libglib2.0-dev

When building from git:

$ sudo apt install -y python autotools-dev intltool gettext libtool
# apt install -y python autotools-dev intltool gettext libtool

You might also try using your package manager:

$ sudo apt build-dep mypaint # will get additional deps for MyPaint (GUI)
$ sudo apt build-dep libmypaint # may not exist; included in mypaint
# apt build-dep mypaint # will get additional deps for MyPaint (GUI)
# apt build-dep libmypaint # may not exist; included in mypaint

### Install dependencies (Red Hat and derivatives)

The following works on a minimal CentOS 7 installation:

$ sudo yum install -y gcc gobject-introspection-devel json-c-devel glib2-devel
# yum install -y gcc gobject-introspection-devel json-c-devel glib2-devel

When building from git, you'll want to add:

$ sudo yum install -y git python autoconf intltool gettext libtool
# yum install -y git python autoconf intltool gettext libtool

You might also try your package manager:

$ sudo yum builddep libmypaint

# yum builddep libmypaint

### Install dependencies (OpenSUSE)

Works with a fresh OpenSUSE Tumbleweed Docker image:

# zypper install gcc13 gobject-introspection-devel libjson-c-devel glib2-devel

When building from git:

# zypper install git python311 autoconf intltool gettext-tools libtool

Package manager:

# zypper install libmypaint0

## Build and install

Expand All @@ -67,8 +81,8 @@ The traditional setup works just fine.

$ ./autogen.sh # Only needed when building from git.
$ ./configure
$ sudo make install
$ sudo ldconfig
# make install
# ldconfig

### Maintainer mode

Expand Down Expand Up @@ -110,7 +124,7 @@ This runs all the unit tests.

### Install

$ sudo make install
# make install

Uninstall libmypaint with `make uninstall`.

Expand All @@ -123,22 +137,22 @@ Make sure that pkg-config can see libmypaint before trying to build with it.
If it's not found, you'll need to add the relevant pkgconfig directory to
the `pkg-config` search path. For example, on CentOS, with a default install:

$ sudo sh -c "echo 'PKG_CONFIG_PATH=/usr/local/lib/pkgconfig' >>/etc/environment"
# sh -c "echo 'PKG_CONFIG_PATH=/usr/local/lib/pkgconfig' >>/etc/environment"

Make sure ldconfig can see libmypaint as well

$ sudo ldconfig -p |grep -i libmypaint
# ldconfig -p |grep -i libmypaint

If it's not found, you'll need to add the relevant lib directory to
the LD_LIBRARY_PATH:

$ export LD_LIBRARY_PATH=/usr/local/lib
$ sudo sh -c "echo 'LD_LIBRARY_PATH=/usr/local/lib' >>/etc/environment
# sh -c "echo 'LD_LIBRARY_PATH=/usr/local/lib' >>/etc/environment

Alternatively, you may want to enable /usr/local for libraries. Arch and Redhat derivatives:

$ sudo sh -c "echo '/usr/local/lib' > /etc/ld.so.conf.d/usrlocal.conf"
$ sudo ldconfig
# sh -c "echo '/usr/local/lib' > /etc/ld.so.conf.d/usrlocal.conf"
# ldconfig

## Contributing

Expand Down
7 changes: 5 additions & 2 deletions autogen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
# tools and you shouldn't use this script. Just call ./configure
# directly.

ACLOCAL=${ACLOCAL-aclocal-1.16}
ACLOCAL=${ACLOCAL-aclocal-1.17}
AUTOCONF=${AUTOCONF-autoconf}
AUTOHEADER=${AUTOHEADER-autoheader}
AUTOMAKE=${AUTOMAKE-automake-1.16}
AUTOMAKE=${AUTOMAKE-automake-1.17}
LIBTOOLIZE=${LIBTOOLIZE-libtoolize}
PYTHON=${PYTHON-python}

Expand Down Expand Up @@ -128,6 +128,9 @@ printf "checking for automake >= $AUTOMAKE_REQUIRED_VERSION ... "
if ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1; then
AUTOMAKE=$AUTOMAKE
ACLOCAL=$ACLOCAL
elif (automake-1.17 --version) < /dev/null > /dev/null 2>&1; then
AUTOMAKE=automake-1.17
ACLOCAL=aclocal-1.17
elif (automake-1.16 --version) < /dev/null > /dev/null 2>&1; then
AUTOMAKE=automake-1.16
ACLOCAL=aclocal-1.16
Expand Down
88 changes: 73 additions & 15 deletions generate.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env python
# libmypaint - The MyPaint Brush Library
# Copyright (C) 2007-2012 Martin Renold <martinxyz@gmx.ch>
# Copyright (C) 2012-2016 by the MyPaint Development Team.
# Copyright (C) 2012-2020 by the MyPaint Development Team.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
Expand All @@ -20,14 +20,56 @@

from __future__ import absolute_import, division, print_function

import json
import json.decoder
import json.scanner
import os
import sys
from os.path import basename
import json
from collections import namedtuple


PY3 = sys.version_info >= (3,)

# == JSON parser wrapper == #

# In order to get the line number from the original json file, this minimal
# wrapper of the standard parser produces tuples for string values where
# the first item is a (line, column) tuple. Complexity is quadratic due to
# naive (but convenient) calculations of lines/columns, so don't use this
# hack for anything heavy.


def _linecol(s, pos):
ss = s[:pos]
line = ss.count('\n') + 1
column = len(ss[ss.rfind('\n') + 1:]) + 1
return (line, column)


def _linecol_scanstring(s, end, *args, **kwds):
result, real_end = json.decoder.py_scanstring(s, end, *args, **kwds)
return (_linecol(s, end - 1), result), real_end


def _normalize(n): # Strip away the linecol component from keys
def _n(t):
return t[1] if isinstance(t, tuple) else t
if isinstance(n, dict):
return {_n(k): _normalize(v) for k, v in n.items()}
elif isinstance(n, list):
return [_normalize(v) for v in n]
else:
return n


def loads(*args, **kwds):
decoder = json.decoder.JSONDecoder()
decoder.parse_string = _linecol_scanstring
decoder.scan_once = json.scanner.py_make_scanner(decoder)
return _normalize(decoder.decode(*args, **kwds))


# A basic translator comment is generated for each string,
# noting whether it is an input or a setting, and for tooltips
# stating which input/setting it belongs to.
Expand Down Expand Up @@ -63,11 +105,18 @@
]
_STATES = [] # brushsettings.states

_ORIG_FILE = "brushsettings.json"


class _BrushSetting (namedtuple("_BrushSetting", _SETTING_ORDER)):

def __init__(self, *args, **kwds):
super(_BrushSetting, self).__init__()
self.real_internal_name = self.internal_name[1]
self.real_displayed_name = self.displayed_name[1]

def validate(self):
msg = "Failed to validate %s: %r" % (self.internal_name, self)
msg = "Failed to validate %s: %r" % (self.real_internal_name, self)
if self.minimum and self.maximum:
assert (self.minimum <= self.default), msg
assert (self.maximum >= self.default), msg
Expand All @@ -77,8 +126,14 @@ def validate(self):

class _BrushInput (namedtuple("_BrushInput", _INPUT_ORDER)):

def __init__(self, *args, **kwds):
self.anything = "nothing"
super(_BrushInput, self).__init__()
self.real_id = self.id[1]
self.real_displayed_name = self.displayed_name[1]

def validate(self):
msg = "Failed to validate %s: %r" % (self.id, self)
msg = "Failed to validate %s: %r" % (self.real_id, self)
if self.hard_maximum is not None:
assert (self.hard_maximum >= self.soft_maximum), msg
assert (self.hard_maximum >= self.normal), msg
Expand All @@ -103,7 +158,7 @@ def with_comments(d):

flag = "r" if PY3 else "rb"
with open(filename, flag) as fp:
defs = json.load(fp)
defs = loads(fp.read())
for input_def in defs["inputs"]:
input = _BrushInput(**with_comments(input_def))
input.validate()
Expand All @@ -112,7 +167,7 @@ def with_comments(d):
setting = _BrushSetting(**with_comments(setting_def))
setting.validate()
_SETTINGS.append(setting)
for state_name in defs["states"]:
for _, state_name in defs["states"]:
_STATES.append(state_name)


Expand Down Expand Up @@ -167,8 +222,10 @@ def floatify(value, positive_inf=True):
return str(value)


def gettextify(value, comment=None):
def gettextify(annotated_value, comment=None):
(line, _), value = annotated_value
result = "N_(%s)" % stringify(value)
result = "/*: ../%s:%d */ %s" % (_ORIG_FILE, line, result)
if comment:
assert isinstance(comment, str) or isinstance(comment, unicode)
result = "/* %s */ %s" % (comment, result)
Expand All @@ -182,7 +239,7 @@ def boolify(value):
def tcomment(base_comment, addendum=None):
comment = base_comment
if addendum:
comment = "{c} - {a}".format(c=comment, a=addendum)
comment = "{c} - {a}".format(c=comment, a=addendum[1])
return comment


Expand All @@ -195,9 +252,9 @@ def tooltip_comment(name, name_type, addendum=None):
def input_info_struct(i):
name_comment = tcomment("Brush input", i.tcomment_name)
_tooltip_comment = tooltip_comment(
i.displayed_name, "input", i.tcomment_tooltip)
i.real_displayed_name, "input", i.tcomment_tooltip)
return (
stringify(i.id),
stringify(i.real_id),
floatify(i.hard_minimum, positive_inf=False),
floatify(i.soft_minimum, positive_inf=False),
floatify(i.normal),
Expand All @@ -211,9 +268,9 @@ def input_info_struct(i):
def settings_info_struct(s):
name_comment = tcomment("Brush setting", s.tcomment_name)
_tooltip_comment = tooltip_comment(
s.displayed_name, "setting", s.tcomment_tooltip)
s.real_displayed_name, "setting", s.tcomment_tooltip)
return (
stringify(s.internal_name),
stringify(s.real_internal_name),
gettextify(s.displayed_name, name_comment),
boolify(s.constant),
floatify(s.minimum, positive_inf=False),
Expand Down Expand Up @@ -256,14 +313,14 @@ def generate_public_settings_code():
"MyPaintBrushInput",
"MYPAINT_BRUSH_INPUT_",
"MYPAINT_BRUSH_INPUTS_COUNT",
enumerate([i.id.upper() for i in _INPUTS]),
enumerate([i.real_id.upper() for i in _INPUTS]),
)
content += '\n'
content += generate_enum(
"MyPaintBrushSetting",
"MYPAINT_BRUSH_SETTING_",
"MYPAINT_BRUSH_SETTINGS_COUNT",
enumerate([i.internal_name.upper() for i in _SETTINGS]),
enumerate([i.real_internal_name.upper() for i in _SETTINGS]),
)
content += '\n'
content += generate_enum(
Expand All @@ -277,8 +334,9 @@ def generate_public_settings_code():


if __name__ == '__main__':
_init_globals_from_json("brushsettings.json")
script = sys.argv[0]
source = os.path.join(os.path.dirname(script), _ORIG_FILE)
_init_globals_from_json(source)
try:
public_header_file, internal_header_file = sys.argv[1:]
except Exception:
Expand Down
2 changes: 1 addition & 1 deletion mypaint-brush.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ brush_reset(MyPaintBrush *self)
int min_index = self->min_bucket_used;
if (min_index != -1) {
int max_index = self->max_bucket_used;
size_t num_bytes = (max_index - min_index) * sizeof(self->smudge_buckets[0]) * SMUDGE_BUCKET_SIZE;
size_t num_bytes = (max_index - min_index + 1) * sizeof(self->smudge_buckets[0]) * SMUDGE_BUCKET_SIZE;
memset(self->smudge_buckets + min_index, 0, num_bytes);
self->min_bucket_used = -1;
self->max_bucket_used = -1;
Expand Down
Loading