Initial checkin of Pika from heckimp
This commit is contained in:
88
tools/colorsvg2png.c
Normal file
88
tools/colorsvg2png.c
Normal file
@ -0,0 +1,88 @@
|
||||
/* colorsvg2png.c
|
||||
* Copyright (C) 2018 Jehan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <glib/gprintf.h>
|
||||
#include <librsvg/rsvg.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
RsvgHandle *handle;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
RsvgRectangle target_rect;
|
||||
|
||||
gchar *input;
|
||||
gchar *output;
|
||||
gint dim;
|
||||
gint retval = 0;
|
||||
|
||||
if (argc != 4)
|
||||
{
|
||||
g_fprintf (stderr, "Usage: colorsvg2png svg-image png-output size\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
input = argv[1];
|
||||
output = argv[2];
|
||||
dim = (gint) g_ascii_strtoull (argv[3], NULL, 10);
|
||||
if (dim < 1)
|
||||
{
|
||||
g_fprintf (stderr, "Usage: invalid dimension %d\n", dim);
|
||||
return 1;
|
||||
}
|
||||
|
||||
handle = rsvg_handle_new_from_file (input, &error);
|
||||
if (! handle)
|
||||
{
|
||||
g_fprintf (stderr,
|
||||
"Error: failed to load '%s' as SVG: %s\n",
|
||||
input, error->message);
|
||||
g_error_free (error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, dim, dim);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
target_rect.x = target_rect.y = 0;
|
||||
target_rect.width = target_rect.height = dim;
|
||||
|
||||
if (! rsvg_handle_render_document (handle, cr, &target_rect, NULL))
|
||||
{
|
||||
g_fprintf (stderr,
|
||||
"Error: failed to render '%s'\n",
|
||||
input);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
if (retval == 0 &&
|
||||
cairo_surface_write_to_png (surface, output) != CAIRO_STATUS_SUCCESS)
|
||||
{
|
||||
g_fprintf (stderr,
|
||||
"Error: failed to write '%s'\n",
|
||||
output);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
cairo_surface_destroy (surface);
|
||||
cairo_destroy (cr);
|
||||
g_object_unref (handle);
|
||||
|
||||
return retval;
|
||||
}
|
86
tools/compute-svg-viewbox.c
Normal file
86
tools/compute-svg-viewbox.c
Normal file
@ -0,0 +1,86 @@
|
||||
/* compute-svg-viewbox.c
|
||||
* Copyright (C) 2016 Jehan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <librsvg/rsvg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
RsvgHandle *handle;
|
||||
RsvgRectangle viewport = { 0.0, 0.0, 16.0, 16.0 };
|
||||
RsvgRectangle out_ink_rect;
|
||||
RsvgRectangle out_logical_rect;
|
||||
|
||||
gchar *endptr;
|
||||
gchar *path;
|
||||
gchar *id;
|
||||
gint prev_x;
|
||||
gint prev_y;
|
||||
|
||||
if (argc != 5)
|
||||
{
|
||||
fprintf (stderr, "Usage: compute-svg-viewbox path object_id x y\n");
|
||||
return 1;
|
||||
}
|
||||
prev_x = strtol (argv[3], &endptr, 10);
|
||||
if (endptr == argv[3])
|
||||
{
|
||||
fprintf (stderr, "Error: the third parameter must be an integer\n");
|
||||
return 1;
|
||||
}
|
||||
prev_y = strtol (argv[4], &endptr, 10);
|
||||
if (endptr == argv[4])
|
||||
{
|
||||
fprintf (stderr, "Error: the fourth parameter must be an integer\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
path = argv[1];
|
||||
handle = rsvg_handle_new_from_file (path, NULL);
|
||||
if (! handle)
|
||||
{
|
||||
fprintf (stderr, "Error: wrong path \"%s\".\n", path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
id = g_strdup_printf ("#%s", argv[2]);
|
||||
if (! rsvg_handle_has_sub (handle, id))
|
||||
{
|
||||
fprintf (stderr, "Error: the id \"%s\" does not exist.\n", id);
|
||||
g_object_unref (handle);
|
||||
g_free (id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
rsvg_handle_get_geometry_for_layer (handle, id, &viewport, &out_ink_rect, &out_logical_rect, NULL);
|
||||
|
||||
if (out_ink_rect.width != out_ink_rect.height)
|
||||
{
|
||||
/* Right now, we are constraining all objects into square objects. */
|
||||
fprintf (stderr, "WARNING: object \"%s\" has unexpected size %fx%f [pos: (%f, %f)].\n",
|
||||
id, out_ink_rect.width, out_ink_rect.height,
|
||||
out_ink_rect.x, out_ink_rect.y);
|
||||
}
|
||||
printf ("viewBox=\"%f %f %f %f\"",
|
||||
out_ink_rect.x + prev_x, out_ink_rect.y + prev_y,
|
||||
out_ink_rect.width, out_ink_rect.height);
|
||||
|
||||
g_object_unref (handle);
|
||||
g_free (id);
|
||||
return 0;
|
||||
}
|
131
tools/defcheck.py
Normal file
131
tools/defcheck.py
Normal file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
defcheck.py -- Consistency check for the .def files.
|
||||
Copyright (C) 2006 Simon Budig <simon@gimp.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
This is a hack to check the consistency of the .def files compared to
|
||||
the respective libraries.
|
||||
|
||||
Invoke in the top level of the pika source tree after compiling PIKA.
|
||||
If srcdir != builddir, run it in the build directory and pass the name
|
||||
of the source directory on the command-line.
|
||||
|
||||
Needs the tool "nm" to work
|
||||
|
||||
"""
|
||||
|
||||
import sys, subprocess
|
||||
|
||||
from os import path
|
||||
|
||||
def_files = (
|
||||
"libpikabase/pikabase.def",
|
||||
"libpikacolor/pikacolor.def",
|
||||
"libpikaconfig/pikaconfig.def",
|
||||
"libpika/pika.def",
|
||||
"libpika/pikaui.def",
|
||||
"libpikamath/pikamath.def",
|
||||
"libpikamodule/pikamodule.def",
|
||||
"libpikathumb/pikathumb.def",
|
||||
"libpikawidgets/pikawidgets.def"
|
||||
)
|
||||
|
||||
have_errors = 0
|
||||
|
||||
srcdir = None
|
||||
if len(sys.argv) > 1:
|
||||
srcdir = sys.argv[1]
|
||||
if not path.exists(srcdir):
|
||||
print("Directory '%s' does not exist" % srcdir)
|
||||
sys.exit (-1)
|
||||
|
||||
for df in def_files:
|
||||
directory, name = path.split (df)
|
||||
basename, extension = name.split (".")
|
||||
libname = path.join(directory, ".libs", "lib" + basename + "-*.so")
|
||||
|
||||
filename = df
|
||||
if srcdir:
|
||||
filename = path.join(srcdir, df)
|
||||
try:
|
||||
defsymbols = open (filename).read ().split ()[1:]
|
||||
except IOError as message:
|
||||
print(message)
|
||||
if not srcdir:
|
||||
print("You should run this script from the toplevel source directory.")
|
||||
sys.exit (-1)
|
||||
|
||||
doublesymbols = []
|
||||
for i in range (len (defsymbols)-1, 0, -1):
|
||||
if defsymbols[i] in defsymbols[:i]:
|
||||
doublesymbols.append ((defsymbols[i], i+2))
|
||||
|
||||
unsortindex = -1
|
||||
for i in range (len (defsymbols)-1):
|
||||
if defsymbols[i] > defsymbols[i+1]:
|
||||
unsortindex = i+1
|
||||
break;
|
||||
|
||||
status, nm = subprocess.getstatusoutput ("nm --defined-only --extern-only " +
|
||||
libname)
|
||||
if status != 0:
|
||||
libname_meson = path.join(directory, "lib" + basename + "-*.so")
|
||||
status, nm = subprocess.getstatusoutput ("nm --defined-only --extern-only " +
|
||||
libname_meson)
|
||||
if status != 0:
|
||||
print("trouble reading {} or {} - has it been compiled?".format(libname, libname_meson))
|
||||
have_errors = -1
|
||||
continue
|
||||
|
||||
nmsymbols = nm.split()[2::3]
|
||||
nmsymbols = [s for s in nmsymbols if s[0] != '_']
|
||||
|
||||
missing_defs = [s for s in nmsymbols if s not in defsymbols]
|
||||
missing_nms = [s for s in defsymbols if s not in nmsymbols]
|
||||
|
||||
if unsortindex >= 0 or missing_defs or missing_nms or doublesymbols:
|
||||
print()
|
||||
print("Problem found in", filename)
|
||||
|
||||
if missing_defs:
|
||||
print(" the following symbols are in the library,")
|
||||
print(" but are not listed in the .def-file:")
|
||||
for s in missing_defs:
|
||||
print(" +", s)
|
||||
print()
|
||||
|
||||
if missing_nms:
|
||||
print(" the following symbols are listed in the .def-file,")
|
||||
print(" but are not exported by the library.")
|
||||
for s in missing_nms:
|
||||
print(" -", s)
|
||||
print()
|
||||
|
||||
if doublesymbols:
|
||||
print(" the following symbols are listed multiple times in the .def-file,")
|
||||
for s in doublesymbols:
|
||||
print(" : %s (line %d)" % s)
|
||||
print()
|
||||
|
||||
if unsortindex >= 0:
|
||||
print(" the .def-file is not properly sorted (line %d)" % (unsortindex + 2))
|
||||
print()
|
||||
|
||||
have_errors = -1
|
||||
|
||||
sys.exit (have_errors)
|
121
tools/extract-vector-icon.sh
Normal file
121
tools/extract-vector-icon.sh
Normal file
@ -0,0 +1,121 @@
|
||||
#!/bin/sh
|
||||
# extract-vector-icon.sh
|
||||
# Copyright (C) 2016 Jehan
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# This script generates a new SVG file by extracting a single object by
|
||||
# its id, from a source SVG, and updating the viewBox (canvas) size and
|
||||
# position.
|
||||
usage ()
|
||||
{
|
||||
printf "Usage: extract-vector-icon.sh source icon-name [width height]\n"
|
||||
printf "Create the file 'icon-name.svg' from the \`source\` SVG.\n"
|
||||
}
|
||||
|
||||
if [ "$#" != 2 ]; then
|
||||
if [ "$#" != 4 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# The script is run from $(top_builddir)/icons/*/
|
||||
compute_viewbox="$(pwd)/../../tools/compute-svg-viewbox"
|
||||
source="$1"
|
||||
id="$2"
|
||||
if [ "$#" = 4 ]; then
|
||||
# The expected display width/height for the image.
|
||||
width="$3"
|
||||
height="$4"
|
||||
else
|
||||
# We base the design of our scalable icons on 16x16 pixels.
|
||||
width="16"
|
||||
height="16"
|
||||
fi
|
||||
|
||||
# Extract the icon code.
|
||||
#icon=`xmllint "$source" --xpath '//*[local-name()="g" and @id="'$id'"]'`
|
||||
icon=`xmllint "$source" --xpath '//*[@id="'$id'"]' --noblanks`
|
||||
# Get rid of any transform on the top node to help librsvg.
|
||||
#icon=`echo $icon | sed 's/^\(<[^>]*\) transform="[^"]*"/\1/'`
|
||||
if [ $? -ne 0 ]; then
|
||||
>&2 echo "extract-vector-icon.sh: object id \"$id\" not found in \"$source\" ";
|
||||
exit 1;
|
||||
fi;
|
||||
|
||||
# Add !important to any object with label "color-important".
|
||||
icon=`echo $icon | sed 's/<\([^<>]*\)style="\([^"]*\)fill:\([^;"]*\)\([^"]*\)"\([^<>]*\)inkscape:label="color-important"\([^>]*\)>/<\1style="\2fill:\3 !important\4"\5\6>/'`
|
||||
icon=`echo $icon | sed 's/<\([^<>]*\)inkscape:label="color-important"\([^>]*\)style="\([^"]*\)fill:\([^;"]*\)\([^"]*\)"\([^<>]*\)>/<\1\2style="\3fill:\4 !important\5"\6>/'`
|
||||
|
||||
# The typical namespaces declared at start of a SVG made with Inkscape.
|
||||
# Since we are not sure of what namespace will use the object XML, and
|
||||
# since we don't want to end up with invalid XML, we just keep them all
|
||||
# declared here.
|
||||
svg_start='<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created by PIKA build. -->
|
||||
|
||||
<svg
|
||||
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
'
|
||||
|
||||
# Grab the defined color palette.
|
||||
defs=`xmllint "$source" --xpath '//*[local-name()="defs"]'`
|
||||
|
||||
# Create a temporary SVG file with the main information.
|
||||
svg_temp="`mktemp ./${id}-XXXX.svg`"
|
||||
echo "$svg_start>$defs$icon</svg>" > $svg_temp
|
||||
|
||||
x=0
|
||||
y=0
|
||||
# In case the source SVG has a viewBox not starting at (0, 0), get
|
||||
# the current origin coordinates.
|
||||
#viewBox=`xmllint $svg_temp --xpath '/*[local-name()="svg"]/@viewBox'`
|
||||
#if [ $? -eq 0 ]; then
|
||||
# x=`echo $viewBox| sed 's/ *viewBox *= *"\([0-9]\+\) .*$/\1/'`
|
||||
# y=`echo $viewBox| sed 's/ *viewBox *= *"[0-9]\+ \+\([0-9]\+\).*$/\1/'`
|
||||
#fi;
|
||||
|
||||
# Compute the viewBox that we want to set to our generated SVG.
|
||||
viewBox=`$compute_viewbox "$svg_temp" "$id" $x $y`
|
||||
if [ $? -ne 0 ]; then
|
||||
>&2 echo "extract-vector-icon.sh: error running \`$compute_viewbox "$tmp" "$id" $x $y\`.";
|
||||
rm -f $svg_temp
|
||||
exit 1;
|
||||
fi;
|
||||
rm -f $svg_temp
|
||||
|
||||
# The finale SVG file with properly set viewBox.
|
||||
svg="$svg_start $viewBox"
|
||||
if [ "$#" = 5 ]; then
|
||||
svg="$svg
|
||||
width=\"$width\"
|
||||
height=\"$height\""
|
||||
fi
|
||||
svg="$svg>
|
||||
<title>$id</title>
|
||||
$defs
|
||||
$icon
|
||||
</svg>"
|
||||
|
||||
echo "$svg"
|
186
tools/flatpak-releases
Normal file
186
tools/flatpak-releases
Normal file
@ -0,0 +1,186 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This is a very basic script for developper usage. It has a few known
|
||||
# limitations (feel free to send patches for these):
|
||||
# - It is targetted at PIKA usage primarily, hence able to check only
|
||||
# Flathub (stable and beta remotes) and GNOME-nightly. Yet some
|
||||
# generity is built-in so you can set your own application ID on
|
||||
# command line and it should work.
|
||||
# - It assumes the remotes are named 'flathub', 'flathub-beta' and
|
||||
# 'gnome-nightly' (for stable, beta and nightly branches respectively)
|
||||
# as these are the default names proposed by generated .flatpakref
|
||||
# files (SuggestRemoteName field) when first installing software from
|
||||
# this repository. So most people will have these remotes registered
|
||||
# with these names. Yet it could technically be any name locally and
|
||||
# this script is not verifying this.
|
||||
# - It also assumes the flathub remotes are installed at all (it can't
|
||||
# search without them being installed and won't install these for
|
||||
# you).
|
||||
# - It uses bash because I lazily didn't bother making it portable as
|
||||
# it's really just a tool for core dev testing. Yet we of course
|
||||
# welcome patches if some syntax needs to be rewritten for
|
||||
# portability.
|
||||
|
||||
install=-1
|
||||
show_runtime=0
|
||||
appid=technology.heckin.PIKA
|
||||
remote='flathub'
|
||||
branch='stable'
|
||||
prefix='--user'
|
||||
for var in "$@"
|
||||
do
|
||||
if [[ $var =~ ^-([0-9]+)$ ]]; then
|
||||
install=${BASH_REMATCH[1]}
|
||||
elif [[ $var = '--beta' ]]; then
|
||||
remote='flathub-beta'
|
||||
branch='beta'
|
||||
elif [[ $var = '--nightly' ]]; then
|
||||
remote='gnome-nightly'
|
||||
branch='master'
|
||||
elif [[ $var = '--system' ]]; then
|
||||
prefix='--system'
|
||||
elif [[ $var = '--runtime' ]]; then
|
||||
show_runtime=1
|
||||
elif [[ $var =~ ^- ]]; then
|
||||
echo "Usage: ./flathub-releases [--beta] [--system] [-X] [org.example.app]"
|
||||
echo
|
||||
echo "List all flatpak builds stored on Flathub or GNOME repository."
|
||||
echo "The builds for technology.heckin.PIKA are looked up by default unless"
|
||||
echo "you provide explicitely another AppStream ID."
|
||||
echo
|
||||
echo "Adding a -X number as option install the numbered release"
|
||||
echo "instead of listing them."
|
||||
echo
|
||||
echo "Options:"
|
||||
echo
|
||||
echo "-0: install the last build."
|
||||
echo "-1: install the previous build."
|
||||
echo "-2: install the before-previous build (and so on)."
|
||||
echo "-[0-9]+: and so on..."
|
||||
echo
|
||||
echo "--beta: list or install a beta release"
|
||||
echo "--nightly: list or install a nightly release"
|
||||
echo
|
||||
echo "--runtime: list or install runtimes (can be associated with --beta and --nightly)"
|
||||
echo
|
||||
echo "--system: install as system flatpak (default to user install)"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo
|
||||
echo "* List all beta flatpak bulds:"
|
||||
echo " flathub-releases --beta"
|
||||
echo "* Install 2-build old beta flatpak:"
|
||||
echo "* flathub-releases --beta -2"
|
||||
echo "* Install the latest beta flatpak:"
|
||||
echo "* flathub-releases --beta -0"
|
||||
echo "* List all builds of the runtime used by the beta flatpak:"
|
||||
echo "* flathub-releases --beta --runtime"
|
||||
echo "* Install the previous runtime build to be used by the beta flatpak:"
|
||||
echo "* flathub-releases --beta --runtime -1"
|
||||
exit 1
|
||||
else
|
||||
appid=$var
|
||||
fi
|
||||
done
|
||||
|
||||
package_info_cmd="flatpak remote-info $remote $appid"
|
||||
package_info=`$package_info_cmd 2>&1`
|
||||
got_info="$?"
|
||||
commit_prefix="app"
|
||||
if [ "$got_info" -ne 0 ]; then
|
||||
# By default flatpak will just use either the user or system install
|
||||
# depending on what it finds. Funnily the command may fail if the
|
||||
# remote is found not 0 or 1 but 2 times (both on user and system).
|
||||
# Normally it would interactively ask to choose, but in this specific
|
||||
# non-interactive case, it would just silently fail instead. So let's
|
||||
# make a second try on user-installed remote (totally arbitrary
|
||||
# choice).
|
||||
user_system="--user"
|
||||
package_info_cmd="flatpak remote-info $user_system $remote $appid"
|
||||
package_info=`$package_info_cmd 2>&1`
|
||||
got_info="$?"
|
||||
fi
|
||||
if [ "$got_info" -ne 0 ]; then
|
||||
echo "Flathub query failed with the following error: $package_info"
|
||||
exit 2
|
||||
elif [ "$show_runtime" -eq 1 ]; then
|
||||
# With the special --runtime option, we list the associated runtime instead of
|
||||
# the application.
|
||||
runtime=`echo "$package_info" | grep Runtime: |sed 's/^ *Runtime: //'`
|
||||
appid=$runtime
|
||||
# The beta runtime is in the stable repository.
|
||||
if [[ $branch = 'beta' ]]; then
|
||||
remote='flathub'
|
||||
fi
|
||||
package_info_cmd="flatpak remote-info $user_system $remote $appid//$branch"
|
||||
|
||||
package_info=`$package_info_cmd 2>&1`
|
||||
got_info="$?"
|
||||
|
||||
if [ "$got_info" -ne 0 ]; then
|
||||
if [ -z "$user_system" ]; then
|
||||
# Do the user/system dance again. Previously we were doing this about the
|
||||
# main package, not its runtime.
|
||||
user_system="--user"
|
||||
package_info_cmd="flatpak remote-info $user_system $remote $appid//$branch"
|
||||
package_info=`$package_info_cmd 2>&1`
|
||||
got_info="$?"
|
||||
fi
|
||||
if [ "$got_info" -ne 0 ]; then
|
||||
echo "Flathub query failed with the following error: $package_info"
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
commit_prefix="runtime"
|
||||
fi
|
||||
|
||||
release_number=0
|
||||
install_commit=
|
||||
while [ "$got_info" -eq 0 ]
|
||||
do
|
||||
release_date=`echo "$package_info" | grep Date: |sed 's/^ *Date: //'`
|
||||
release_commit=`echo "$package_info" | grep Commit: |sed 's/^ *Commit: //'`
|
||||
release_subject=`echo "$package_info" | grep Subject: |sed 's/^ *Subject: //'`
|
||||
if [ "$install" -eq -1 ]; then
|
||||
# In non-install mode, just list the whole release.
|
||||
printf "%2d: %s [%s] - $commit_prefix-commit: %s\n" $release_number "$release_subject" "$release_date" "$release_commit"
|
||||
elif [ "$install" -eq "$release_number" ]; then
|
||||
install_commit=$release_commit
|
||||
break
|
||||
fi
|
||||
|
||||
parent_commit=`echo "$package_info" | grep Parent: |sed 's/^ *Parent: //'`
|
||||
release_number=$(( $release_number + 1 ))
|
||||
|
||||
package_info=`$package_info_cmd --commit $parent_commit 2>&1`
|
||||
got_info="$?"
|
||||
done
|
||||
|
||||
if [ "$install" -ne -1 ]; then
|
||||
if [ -n "$install_commit" ]; then
|
||||
# Flatpak doesn't have a way to install directly a commit, but we
|
||||
# can install then update. This will work whether the flatpak is
|
||||
# already installed or not.
|
||||
|
||||
echo "[1/2] Installing $appid"
|
||||
flatpak install -y $prefix $remote $appid//$branch
|
||||
|
||||
echo "[2/2] Updating to commit '$install_commit' ($release_number's previous build)"
|
||||
flatpak update -y $prefix --commit=$install_commit $appid//$branch
|
||||
|
||||
if [ "$?" -eq 0 ]; then
|
||||
echo "Build $release_number released on $release_date was installed."
|
||||
echo "Build subject: $release_subject"
|
||||
echo "Build commit on $remote: $release_commit"
|
||||
else
|
||||
echo "Failure to install build $release_number released on $release_date."
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
echo "There was no $release_number's build to install. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
229
tools/generate-icon-makefiles.py
Normal file
229
tools/generate-icon-makefiles.py
Normal file
@ -0,0 +1,229 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
generate-icon-makefiles.py -- Generate icons/(Color|Symbolic)/icon-list.mk
|
||||
Copyright (C) 2022 Jehan
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: generate-icon-makefiles.py
|
||||
"""
|
||||
|
||||
import os.path
|
||||
|
||||
tools_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
icons_dir = os.path.join(tools_dir, '../icons')
|
||||
|
||||
list_dir = os.path.join(icons_dir, 'icon-lists')
|
||||
|
||||
color_mk = os.path.join(icons_dir, 'Color', 'icon-list.mk')
|
||||
symbolic_mk = os.path.join(icons_dir, 'Symbolic', 'icon-list.mk')
|
||||
|
||||
def print_icons(indir, filenames, max_len, prefix, suffix, outfile, endlist=True):
|
||||
icons = []
|
||||
for filename in filenames:
|
||||
icon_list = os.path.join(indir, filename)
|
||||
with open(icon_list, mode='r') as f:
|
||||
icons += [line.strip() for line in f]
|
||||
# Replace comment lines with empty strings.
|
||||
prev_blank = False
|
||||
pop_list = []
|
||||
for i, icon in enumerate(icons):
|
||||
if icon != '' and icon[0] == '#':
|
||||
icons[i] = ''
|
||||
if icons[i] == '':
|
||||
if prev_blank:
|
||||
pop_list += [i]
|
||||
prev_blank = True
|
||||
else:
|
||||
prev_blank = False
|
||||
if icons[i] in icons[:i]:
|
||||
pop_list += [i]
|
||||
pop_list.reverse()
|
||||
for i in pop_list:
|
||||
# Remove successive blanks and duplicate icons.
|
||||
icons.pop(i)
|
||||
# Strip empty lines in extremities.
|
||||
while icons[-1] == '':
|
||||
icons.pop()
|
||||
while icons[0] == '':
|
||||
icons.pop(0)
|
||||
|
||||
if max_len is None:
|
||||
max_len = len(max(icons, key=len)) + len(prefix + suffix)
|
||||
|
||||
prev_empty = False
|
||||
|
||||
# Using tabs, displayed as 8 chars in our coding style. Computing
|
||||
# needed tabs for proper alignment.
|
||||
needed_tabs = int(max_len / 8) + (1 if max_len % 8 != 0 else 0)
|
||||
for icon in icons[:-1]:
|
||||
if icon == '':
|
||||
# Only keep one empty line.
|
||||
if not prev_empty:
|
||||
print("\t\\", file=outfile)
|
||||
prev_empty = True
|
||||
else:
|
||||
icon_path = prefix + icon + suffix
|
||||
tab_mult = needed_tabs - int(len(icon_path) / 8) + 1
|
||||
icon_path = "\t{}{}\\".format(icon_path, "\t" * tab_mult)
|
||||
print(icon_path, file=outfile)
|
||||
prev_empty = False
|
||||
else:
|
||||
if endlist:
|
||||
icon_path = "\t{}".format(prefix) + icons[-1] + suffix
|
||||
print(icon_path, file=outfile)
|
||||
else:
|
||||
icon_path = prefix + icons[-1] + suffix
|
||||
tab_mult = needed_tabs - int(len(icon_path) / 8) + 1
|
||||
icon_path = "\t{}{}\\".format(icon_path, "\t" * tab_mult)
|
||||
print(icon_path, file=outfile)
|
||||
|
||||
return max_len
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
with open(color_mk, mode='w') as colorf, open(symbolic_mk, mode='w') as symbolicf:
|
||||
top_comment = '''
|
||||
## --------------------------------------------------------------
|
||||
## This file is autogenerated by tools/generate-icon-makefiles.py
|
||||
## --------------------------------------------------------------
|
||||
|
||||
## Modify this script or files inside icons/icon-lists/ instead of this one.
|
||||
## Then run tools/generate-icon-makefiles.py again.
|
||||
'''
|
||||
print(top_comment, file=colorf)
|
||||
print(top_comment, file=symbolicf)
|
||||
|
||||
# Scalable icons.
|
||||
print("scalable_images = \\", file=colorf)
|
||||
print("scalable_images = \\", file=symbolicf)
|
||||
|
||||
# Let's assume that scalable icons are the biggest list since it
|
||||
# should contain nearly all images. So we compute max_len once and
|
||||
# reuse this value on all lists.
|
||||
col_max_len = print_icons(list_dir,
|
||||
['scalable.list',
|
||||
'color-selectors.list', 'controllers.list', 'display-filters.list',
|
||||
'locks.list', 'prefs.list', 'templates.list', 'tools.list'],
|
||||
None, "scalable/", ".svg", colorf)
|
||||
sym_max_len = print_icons(list_dir,
|
||||
['scalable.list',
|
||||
'color-selectors.list', 'controllers.list', 'display-filters.list',
|
||||
'locks.list', 'prefs.list', 'templates.list', 'tools.list'],
|
||||
None, "scalable/", "-symbolic.svg", symbolicf)
|
||||
|
||||
# 12x12 bitmap
|
||||
print("\nicons12_images = \\", file=colorf)
|
||||
print("\nicons12_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_12.list'], col_max_len, "12/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_12.list'], sym_max_len, "12/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 16x16 bitmap
|
||||
print("\nicons16_images = \\", file=colorf)
|
||||
print("\nicons16_images = \\", file=symbolicf)
|
||||
print_icons(list_dir,
|
||||
['bitmap_16.list',
|
||||
'color-selectors.list', 'controllers.list', 'display-filters.list',
|
||||
'locks.list', 'prefs.list', 'templates.list', 'tools.list'],
|
||||
col_max_len, "16/", ".png", colorf)
|
||||
print_icons(list_dir,
|
||||
['bitmap_16.list',
|
||||
'color-selectors.list', 'controllers.list', 'display-filters.list',
|
||||
'locks.list', 'prefs.list', 'templates.list', 'tools.list'],
|
||||
sym_max_len, "16/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 18x18 bitmap
|
||||
print("\nicons18_images = \\", file=colorf)
|
||||
print("\nicons18_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_18.list'], col_max_len, "18/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_18.list'], sym_max_len, "18/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 22x22 bitmap
|
||||
print("\nicons22_images = \\", file=colorf)
|
||||
print("\nicons22_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_22.list'], col_max_len, "22/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_22.list'], sym_max_len, "22/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 24x24 bitmap
|
||||
print("\nicons24_images = \\", file=colorf)
|
||||
print("\nicons24_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_24.list', 'templates.list', 'tools.list'],
|
||||
col_max_len, "24/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_24.list', 'templates.list', 'tools.list'],
|
||||
sym_max_len, "24/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 32x32 bitmap
|
||||
print("\nicons32_images = \\", file=colorf)
|
||||
print("\nicons32_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_32.list'], col_max_len, "32/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_32.list'], sym_max_len, "32/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 48x48 bitmap
|
||||
print("\nicons48_images = \\", file=colorf)
|
||||
print("\nicons48_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_48.list', 'prefs.list'], col_max_len, "48/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_48.list', 'prefs.list'], sym_max_len, "48/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 64x64 bitmap
|
||||
print("\nicons64_images = \\", file=colorf)
|
||||
print("\nicons64_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, [ 'bitmap_64-always.list', 'bitmap_64.list'], col_max_len, "64/", ".png", colorf)
|
||||
print_icons(list_dir, [ 'bitmap_64-always.list' ], sym_max_len, "64/", ".png", symbolicf, endlist=False)
|
||||
print_icons(list_dir, [ 'bitmap_64.list'], sym_max_len, "64/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
print("\nicons64_system_images = \\", file=colorf)
|
||||
print("\nicons64_system_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_64-system.list'], col_max_len, "64/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_64-system.list'], sym_max_len, "64/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 96x96 bitmap
|
||||
print("\nicons96_images = \\", file=colorf)
|
||||
print("\nicons96_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_96.list'], col_max_len, "96/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_96.list'], sym_max_len, "96/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 128x128 bitmap
|
||||
print("\nicons128_images = \\", file=colorf)
|
||||
print("\nicons128_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_128.list'], col_max_len, "128/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_128.list'], sym_max_len, "128/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 192x192 bitmap
|
||||
print("\nicons192_images = \\", file=colorf)
|
||||
print("\nicons192_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_192.list'], col_max_len, "192/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_192.list'], sym_max_len, "192/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
# 256x256 bitmap
|
||||
print("\nicons256_images = \\", file=colorf)
|
||||
print("\nicons256_images = \\", file=symbolicf)
|
||||
print_icons(list_dir, ['bitmap_256.list'], col_max_len, "256/", ".png", colorf)
|
||||
print_icons(list_dir, ['bitmap_256.list'], sym_max_len, "256/", "-symbolic.symbolic.png", symbolicf)
|
||||
|
||||
print(file=colorf)
|
||||
print(file=symbolicf)
|
||||
eof = os.path.join(list_dir, "icon-list.mk.eof")
|
||||
with open(eof, mode='r') as f:
|
||||
for line in f:
|
||||
colorf.write(line)
|
||||
symbolicf.write(line)
|
||||
|
||||
# Touch the 2 meson.build to force-trigger their re-processing (hence
|
||||
# re-configuration) at next build. Otherwise even with image list
|
||||
# changed, meson might not see it as it uses the list from the last
|
||||
# configuration.
|
||||
os.utime(os.path.join(icons_dir, 'Color', 'meson.build'), times=None)
|
||||
os.utime(os.path.join(icons_dir, 'Symbolic', 'meson.build'), times=None)
|
30
tools/generate-news
Normal file
30
tools/generate-news
Normal file
@ -0,0 +1,30 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright (C) 2015 Ville Pätsi <drc@gimp.org>
|
||||
|
||||
SCRIPT_FOLDER=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
|
||||
FIRST_COMMIT="$1"
|
||||
[ -z "$FIRST_COMMIT" ] && FIRST_COMMIT="950412fbdc720fe2600f58f04f25145d9073895d" # First after tag 2.8.0
|
||||
|
||||
declare -a FOLDERS=('app tools menus etc' \
|
||||
'libpika libpikabase libpikacolor libpikaconfig libpikamath libpikamodule libpikathumb libpikawidgets' \
|
||||
'plug-ins' \
|
||||
'modules'
|
||||
'build' \
|
||||
'themes icons')
|
||||
|
||||
OUTPUTFILE=${SCRIPT_FOLDER}/../NEWS_since_"${FIRST_COMMIT}"
|
||||
|
||||
pushd ${SCRIPT_FOLDER}/..
|
||||
|
||||
for folderloop in "${FOLDERS[@]}"
|
||||
do uppercase_folderloop="`echo ${folderloop:0:1} | tr '[:lower:]' '[:upper:]'`${folderloop:1}"
|
||||
echo -e "${uppercase_folderloop}:\n" >> "${OUTPUTFILE}"
|
||||
git log --date-order --reverse --date=short --pretty=format:"- %h %s" "${FIRST_COMMIT}"..HEAD ${folderloop} >> "${OUTPUTFILE}"
|
||||
echo -e "\n\n" >> "${OUTPUTFILE}"
|
||||
done
|
||||
|
||||
popd
|
||||
|
||||
echo "NEWS generated into ${OUTPUTFILE}"
|
154
tools/generate-welcome-dialog-data.py
Normal file
154
tools/generate-welcome-dialog-data.py
Normal file
@ -0,0 +1,154 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
generate-welcome-dialog-data.py -- Generate app/dialogs/welcome-dialog-data.h
|
||||
Copyright (C) 2022 Jehan
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: generate-welcome-dialog-data.py
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
tools_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
desktop_dir = os.path.join(tools_dir, '../desktop')
|
||||
outdir = os.path.join(tools_dir, '../app/dialogs')
|
||||
|
||||
infile = os.path.join(desktop_dir, 'technology.heckin.PIKA.appdata.xml.in.in')
|
||||
outfile = os.path.join(outdir, 'welcome-dialog-data.h')
|
||||
|
||||
def parse_appdata(infile, version):
|
||||
introduction = []
|
||||
release_texts = []
|
||||
release_demos = []
|
||||
|
||||
spaces = re.compile(r'\s+')
|
||||
tree = ET.parse(infile)
|
||||
root = tree.getroot()
|
||||
releases_node = root.find('releases')
|
||||
releases = releases_node.findall('release')
|
||||
for release in releases:
|
||||
if 'version' in release.attrib and release.attrib['version'] == version:
|
||||
intro = release.findall('./description/p')
|
||||
for p in intro:
|
||||
# Naive conversion for C strings, but it will probably fit for
|
||||
# most cases.
|
||||
p = p.text.strip()
|
||||
p = p.replace('\\', '\\\\')
|
||||
p = p.replace('"', '\\"')
|
||||
# All redundant spaces unwanted as XML merges them anyway.
|
||||
introduction += [spaces.sub(' ', p)]
|
||||
|
||||
items = release.findall('./description/ul/li')
|
||||
for item in items:
|
||||
text = item.text.strip()
|
||||
text = text.replace('\\', '\\\\')
|
||||
text = text.replace('"', '\\"')
|
||||
demo = None
|
||||
if 'demo' in item.attrib:
|
||||
demo = item.attrib['demo']
|
||||
# All spaces unneeded in demo string.
|
||||
demo = demo.replace(' ', '')
|
||||
release_texts += [spaces.sub(' ', text)]
|
||||
release_demos += [demo]
|
||||
break
|
||||
|
||||
return introduction, release_texts, release_demos
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('version')
|
||||
parser.add_argument('--header', action='store_true')
|
||||
args = parser.parse_args(sys.argv[1:])
|
||||
|
||||
top_comment = '''/* PIKA - Photo and Image Kooker Application
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* welcome-dialog-data.h
|
||||
* Copyright (C) 2022 Jehan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
***********************************************************************
|
||||
* This file is autogenerated by tools/generate-welcome-dialog-data.py *
|
||||
***********************************************************************
|
||||
*
|
||||
* Modify the python script or desktop/technology.heckin.PIKA.appdata.xml.in.in
|
||||
* instead of this one
|
||||
* Then run tools/generate-welcome-dialog-data.py again.
|
||||
*/
|
||||
|
||||
'''
|
||||
print(top_comment)
|
||||
|
||||
intro_p, items, demos = parse_appdata(infile, args.version)
|
||||
|
||||
if args.header:
|
||||
print('#ifndef __WELCOME_DIALOG_DATA_H__')
|
||||
print('#define __WELCOME_DIALOG_DATA_H__\n\n')
|
||||
|
||||
print('extern gint pika_welcome_dialog_n_items;')
|
||||
print('extern const gchar * pika_welcome_dialog_items[];')
|
||||
print('extern const gchar * pika_welcome_dialog_demos[];')
|
||||
print()
|
||||
print('extern gint pika_welcome_dialog_intro_n_paragraphs;')
|
||||
print('extern const gchar * pika_welcome_dialog_intro[];')
|
||||
|
||||
print('\n\n#endif /* __WELCOME_DIALOG_DATA_H__ */')
|
||||
else:
|
||||
print('#include "config.h"')
|
||||
print('#include <glib.h>')
|
||||
print()
|
||||
|
||||
print('const gint pika_welcome_dialog_n_items = {};'.format(len(demos)))
|
||||
print()
|
||||
print('const gchar *pika_welcome_dialog_items[] =')
|
||||
print('{')
|
||||
for item in items:
|
||||
print(' "{}",'.format(item))
|
||||
print(' NULL,\n};')
|
||||
print()
|
||||
print('const gchar *pika_welcome_dialog_demos[] =')
|
||||
print('{')
|
||||
for demo in demos:
|
||||
if demo is None:
|
||||
print(' NULL,')
|
||||
else:
|
||||
print(' "{}",'.format(demo))
|
||||
print(' NULL,\n};')
|
||||
print()
|
||||
print('const gint pika_welcome_dialog_intro_n_paragraphs = {};'.format(len(intro_p)))
|
||||
print()
|
||||
print('const gchar *pika_welcome_dialog_intro[] =')
|
||||
print('{')
|
||||
for p in intro_p:
|
||||
print(' "{}",'.format(p))
|
||||
print(' NULL,\n};')
|
35
tools/generate_changelog.sh
Normal file
35
tools/generate_changelog.sh
Normal file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
|
||||
srcdir="$1"
|
||||
output="$2"
|
||||
|
||||
echo "Creating ${output} based on git log"
|
||||
|
||||
gitdir="${srcdir}/.git"
|
||||
|
||||
if [[ ! -d "${gitdir}" ]]; then
|
||||
echo "A git checkout and git-log is required to write changelog in ${output}." \
|
||||
| tee ${output} >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
CHANGELOG_START=74424325abb54620b370f2595445b2b2a19fe5e7
|
||||
|
||||
( \
|
||||
git log "${CHANGELOG_START}^.." --stat "${srcdir}" | fmt --split-only \
|
||||
> "${output}.tmp" \
|
||||
&& [ ${PIPESTATUS[0]} -eq 0 ] \
|
||||
&& mv "${output}.tmp" "${output}" -f \
|
||||
&& echo "Appending ChangeLog.pre-git" \
|
||||
&& cat "${srcdir}/ChangeLog.pre-git" >> "${output}" \
|
||||
&& exit 0
|
||||
) \
|
||||
||\
|
||||
( \
|
||||
rm "${output}.tmp" -f \
|
||||
&& echo "Failed to generate ChangeLog, your ChangeLog may be outdated" >&2 \
|
||||
&& (test -f "${output}" \
|
||||
|| echo "git-log is required to generate this file" >> "${output}") \
|
||||
&& exit 1
|
||||
)
|
132
tools/kernelgen.c
Normal file
132
tools/kernelgen.c
Normal file
@ -0,0 +1,132 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* kernelgen -- Copyright (C) 2000 Sven Neumann <sven@gimp.org>
|
||||
*
|
||||
* Simple hack to create brush subsampling kernels. If you want to
|
||||
* play with it, change some of the #defines at the top and copy
|
||||
* the output to app/paint/pikabrushcore-kernels.h.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define STEPS 64
|
||||
#define KERNEL_WIDTH 3 /* changing these makes no sense */
|
||||
#define KERNEL_HEIGHT 3 /* changing these makes no sense */
|
||||
#define KERNEL_SUM 256
|
||||
#define SUBSAMPLE 4
|
||||
#define THRESHOLD 0.25 /* try to change this one */
|
||||
|
||||
#define SQR(x) ((x) * (x))
|
||||
|
||||
static void
|
||||
create_kernel (double x,
|
||||
double y)
|
||||
{
|
||||
double value[KERNEL_WIDTH][KERNEL_HEIGHT];
|
||||
double dist_x;
|
||||
double dist_y;
|
||||
double sum;
|
||||
double w;
|
||||
int i, j;
|
||||
|
||||
memset (value, 0, KERNEL_WIDTH * KERNEL_HEIGHT * sizeof (double));
|
||||
sum = 0.0;
|
||||
|
||||
x += 1.0;
|
||||
y += 1.0;
|
||||
|
||||
for (j = 0; j < STEPS * KERNEL_HEIGHT; j++)
|
||||
{
|
||||
dist_y = y - (((double)j + 0.5) / (double)STEPS);
|
||||
|
||||
for (i = 0; i < STEPS * KERNEL_WIDTH; i++)
|
||||
{
|
||||
dist_x = x - (((double) i + 0.5) / (double) STEPS);
|
||||
|
||||
/* I've tried to use a gauss function here instead of a
|
||||
threshold, but the result was not that impressive. */
|
||||
w = (SQR (dist_x) + SQR (dist_y)) < THRESHOLD ? 1.0 : 0.0;
|
||||
|
||||
value[i / STEPS][j / STEPS] += w;
|
||||
sum += w;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < KERNEL_HEIGHT; j++)
|
||||
{
|
||||
for (i = 0; i < KERNEL_WIDTH; i++)
|
||||
{
|
||||
w = (double) KERNEL_SUM * value[i][j] / sum;
|
||||
printf (" %3d,", (int) (w + 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
int i, j;
|
||||
double x, y;
|
||||
|
||||
printf ("/* pikabrushcore-kernels.h\n"
|
||||
" *\n"
|
||||
" * This file was generated using kernelgen as found in the tools dir.\n");
|
||||
printf (" * (threshold = %g)\n", THRESHOLD);
|
||||
printf (" */\n\n");
|
||||
printf ("#ifndef __PIKA_BRUSH_CORE_KERNELS_H__\n");
|
||||
printf ("#define __PIKA_BRUSH_CORE_KERNELS_H__\n\n");
|
||||
printf ("#define KERNEL_WIDTH %d\n", KERNEL_WIDTH);
|
||||
printf ("#define KERNEL_HEIGHT %d\n", KERNEL_HEIGHT);
|
||||
printf ("#define KERNEL_SUBSAMPLE %d\n", SUBSAMPLE);
|
||||
printf ("#define KERNEL_SUM %d\n", KERNEL_SUM);
|
||||
printf ("\n\n");
|
||||
printf ("/* Brush pixel subsampling kernels */\n");
|
||||
printf ("static const int subsample[%d][%d][%d] =\n{\n",
|
||||
SUBSAMPLE + 1, SUBSAMPLE + 1, KERNEL_WIDTH * KERNEL_HEIGHT);
|
||||
|
||||
for (j = 0; j <= SUBSAMPLE; j++)
|
||||
{
|
||||
y = (double) j / (double) SUBSAMPLE;
|
||||
|
||||
printf (" {\n");
|
||||
|
||||
for (i = 0; i <= SUBSAMPLE; i++)
|
||||
{
|
||||
x = (double) i / (double) SUBSAMPLE;
|
||||
|
||||
printf (" {");
|
||||
create_kernel (x, y);
|
||||
printf (" }%s", i < SUBSAMPLE ? ",\n" : "\n");
|
||||
}
|
||||
|
||||
printf (" }%s", j < SUBSAMPLE ? ",\n" : "\n");
|
||||
}
|
||||
|
||||
printf ("};\n\n");
|
||||
|
||||
printf ("#endif /* __PIKA_BRUSH_CORE_KERNELS_H__ */\n");
|
||||
|
||||
return 0;
|
||||
}
|
53
tools/meson-mkenums.sh
Normal file
53
tools/meson-mkenums.sh
Normal file
@ -0,0 +1,53 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This is a wrapper to the tools/pika-mkenums perl script which:
|
||||
# * sets a few common values;
|
||||
# * updates the ${filebase}enums.c directly in the source directory in
|
||||
# order for it to be versionned.
|
||||
# * Create a no-op stamp-header file to be included by the resulting
|
||||
# enums.c. The goal is to make sure that meson will trigger a rebuild
|
||||
# of the enums.c generation before compiling, if the enums.h changed.
|
||||
# See the explanation here:
|
||||
# https://github.com/mesonbuild/meson/issues/10196#issuecomment-1080742592
|
||||
# This is also the trick used for pdbgen.
|
||||
|
||||
# Arguments to this script:
|
||||
# The perl binary to use.
|
||||
PERL="$1"
|
||||
# Root of the source directory.
|
||||
top_srcdir="$2"
|
||||
# Current source folder.
|
||||
srcdir="$3"
|
||||
# Current build folder.
|
||||
builddir="$4"
|
||||
# Base of the generated enums.c file name.
|
||||
filebase="$5"
|
||||
# Includes before #include "${filebase}enums.h"
|
||||
preincludes="$6"
|
||||
# Includes after #include "${filebase}enums.h"
|
||||
postincludes="$7"
|
||||
# Value for --dtail option if the default doesn't fit.
|
||||
dtail="$8"
|
||||
|
||||
if [ -z "$dtail" ]; then
|
||||
dtail=" { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n pika_type_set_translation_context (type, \"@enumnick@\");\n pika_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n"
|
||||
fi
|
||||
|
||||
$PERL $top_srcdir/tools/pika-mkenums \
|
||||
--fhead "#include \"stamp-${filebase}enums.h\"\n#include \"config.h\"\n$preincludes#include \"${filebase}enums.h\"\n$postincludes" \
|
||||
--fprod "\n/* enumerations from \"@basename@\" */" \
|
||||
--vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \
|
||||
--vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
|
||||
--vtail " { 0, NULL, NULL }\n };\n" \
|
||||
--dhead " static const Pika@Type@Desc descs[] =\n {" \
|
||||
--dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \
|
||||
--dtail "$dtail" \
|
||||
"$srcdir/${filebase}enums.h" > "$builddir/${filebase}enums-tmp.c"
|
||||
|
||||
if ! cmp -s "$builddir/${filebase}enums-tmp.c" "$srcdir/${filebase}enums.c"; then
|
||||
cp "$builddir/${filebase}enums-tmp.c" "$srcdir/${filebase}enums.c";
|
||||
else
|
||||
touch "$srcdir/${filebase}enums.c"; 2> /dev/null || true;
|
||||
fi
|
||||
|
||||
echo "/* Generated on `date`. */" > $builddir/stamp-${filebase}enums.h
|
62
tools/meson.build
Normal file
62
tools/meson.build
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
if platform_windows
|
||||
pika_debug_resume = executable('pika-debug-resume',
|
||||
'pika-debug-resume.c',
|
||||
)
|
||||
endif
|
||||
|
||||
|
||||
pikatool = executable('pikatool' + exec_ver,
|
||||
'pikatool.c',
|
||||
include_directories: rootInclude,
|
||||
dependencies: [
|
||||
gtk3,
|
||||
],
|
||||
link_with: [
|
||||
libpikabase,
|
||||
],
|
||||
c_args: [
|
||||
'-DDATADIR="@0@"'.format(get_option('datadir')),
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
||||
pika_test_clipboard = executable('pika-test-clipboard' + exec_ver,
|
||||
'pika-test-clipboard.c',
|
||||
include_directories: rootInclude,
|
||||
dependencies: [
|
||||
gtk3,
|
||||
],
|
||||
install: true,
|
||||
)
|
||||
|
||||
if enable_default_bin and meson.version().version_compare('>=0.61.0')
|
||||
install_symlink(fs.name(pikatool.full_path()).replace(exec_ver, ''),
|
||||
pointing_to: fs.name(pikatool.full_path()),
|
||||
install_dir: get_option('bindir')
|
||||
)
|
||||
install_symlink(fs.name(pika_test_clipboard.full_path()).replace(exec_ver, ''),
|
||||
pointing_to: fs.name(pika_test_clipboard.full_path()),
|
||||
install_dir: get_option('bindir')
|
||||
)
|
||||
endif
|
||||
|
||||
executable('kernelgen',
|
||||
'kernelgen.c',
|
||||
include_directories: rootInclude,
|
||||
install: false,
|
||||
)
|
||||
|
||||
colorsvg2png = executable('colorsvg2png',
|
||||
'colorsvg2png.c',
|
||||
native: true,
|
||||
dependencies: [
|
||||
native_glib,
|
||||
native_rsvg
|
||||
],
|
||||
# In case b_sanitize was set, we don't really care if the tool has issues (in
|
||||
# particular we experienced some memory leaks with b_sanitize=address, within
|
||||
# librsvg and we don't want this to break the build).
|
||||
override_options: [ 'b_sanitize=none' ],
|
||||
install: false,
|
||||
)
|
99
tools/meson_install_subdir.py
Normal file
99
tools/meson_install_subdir.py
Normal file
@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, os
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
import json
|
||||
|
||||
import shutil
|
||||
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
def __call__(cls, *args, **kwargs):
|
||||
if cls not in cls._instances:
|
||||
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
||||
return cls._instances[cls]
|
||||
|
||||
def copytree(src, dst, symlinks=False, ignore=None):
|
||||
for item in os.listdir(src):
|
||||
s = os.path.join(src, item)
|
||||
d = os.path.join(dst, item)
|
||||
if os.path.isdir(s):
|
||||
shutil.copytree(s, d, symlinks, ignore)
|
||||
else:
|
||||
shutil.copy2(s, d)
|
||||
|
||||
class MesonStatus(metaclass = Singleton):
|
||||
def __init__(self):
|
||||
self.get_build_dir()
|
||||
self.get_meson_info()
|
||||
self.get_meson_installed()
|
||||
|
||||
def get_build_dir(self):
|
||||
self.buildroot = None
|
||||
|
||||
# Set up by meson.
|
||||
cwd = Path(os.environ['MESON_BUILD_ROOT'])
|
||||
|
||||
if (cwd / 'meson-info').exists():
|
||||
self.buildroot = cwd
|
||||
|
||||
if self.buildroot is None:
|
||||
print('Error: build directory was not detected. Are you in it ?')
|
||||
|
||||
def get_meson_info(self):
|
||||
with open(self.buildroot / 'meson-info' / 'meson-info.json') as file:
|
||||
self.meson_info = json.load(file)
|
||||
self.sourceroot = Path(self.meson_info['directories']['source'])
|
||||
|
||||
def get_meson_installed(self):
|
||||
info = self.meson_info['directories']['info']
|
||||
inst = self.meson_info['introspection']['information']['installed']['file']
|
||||
|
||||
with open(Path(info) / inst) as file:
|
||||
self.installed_files = json.load(file)
|
||||
|
||||
|
||||
def get_files_of_part(part_name):
|
||||
files_of_part = {}
|
||||
sourcedir = str(MesonStatus().sourceroot / part_name)
|
||||
builddir = str(MesonStatus().buildroot / part_name)
|
||||
for file, target in MesonStatus().installed_files.items():
|
||||
if file.startswith(sourcedir + '/') or file.startswith(builddir + '/'):
|
||||
files_of_part[file] = target
|
||||
|
||||
return files_of_part
|
||||
|
||||
def install_files(files, verbose):
|
||||
warnings = []
|
||||
for file in sorted(files.keys()):
|
||||
target = files[file]
|
||||
if verbose: print(file + ' → ' + target, end='\n')
|
||||
|
||||
if os.path.isdir(file):
|
||||
copytree(file, target)
|
||||
if os.path.isfile(file):
|
||||
try:
|
||||
shutil.copy2(file, target)
|
||||
except Exception as e:
|
||||
warnings += [(file, e)]
|
||||
if len(warnings) > 0:
|
||||
sys.stderr.write("\n*** WARNING: *** Some file installation failed:\n")
|
||||
for (file, e) in warnings:
|
||||
sys.stderr.write("- {}: {}\n".format(file, e))
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('subdirs', nargs='+')
|
||||
parser.add_argument('--verbose', '-v', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
verbose = args.verbose
|
||||
|
||||
for subdir in args.subdirs:
|
||||
files = get_files_of_part(subdir)
|
||||
if len(files) == 0:
|
||||
print('Error: subdir %s does not contain any installable file' % subdir)
|
||||
install_files(files, verbose)
|
96
tools/mnemonic-clashes
Normal file
96
tools/mnemonic-clashes
Normal file
@ -0,0 +1,96 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir="`dirname \"$0\"`/.."
|
||||
|
||||
find_actions () {
|
||||
for f in "$srcdir"/app/actions/*-actions.c; do
|
||||
< $f \
|
||||
tr '\n' ' ' | \
|
||||
grep -Po '{ *".*?".*?(NC_\("/*?" *, *)?".*?".*?}' | \
|
||||
perl -pe 's/{ *(".*?").*?(?:NC_\(".*?" *, *)?(".*?").*?}/\1: \2,/g'
|
||||
done
|
||||
}
|
||||
|
||||
python3 - $@ <<END
|
||||
from sys import argv
|
||||
from itertools import chain
|
||||
from glob import glob
|
||||
from xml.etree.ElementTree import ElementTree
|
||||
|
||||
actions = {`find_actions`}
|
||||
|
||||
found_clashes = False
|
||||
|
||||
for file in glob ("$srcdir/menus/*.xml*"):
|
||||
tree = ElementTree (file = file)
|
||||
|
||||
parents = {c: p for p in tree.iter () for c in p}
|
||||
|
||||
def menu_path (menu):
|
||||
path = ""
|
||||
|
||||
while menu:
|
||||
if menu.tag == "menu":
|
||||
if path:
|
||||
path = " -> " + path
|
||||
|
||||
path = menu.get ("name") + path
|
||||
|
||||
menu = parents.get (menu)
|
||||
|
||||
return path
|
||||
|
||||
for menu in chain (tree.iter ("menubar-and-popup"),
|
||||
tree.iter ("menu"),
|
||||
tree.iter ("popup")):
|
||||
if len (argv) > 1 and menu.tag != argv[1]:
|
||||
continue
|
||||
|
||||
mnemonics = {}
|
||||
|
||||
found_clashes_in_menu = False
|
||||
|
||||
for element in menu:
|
||||
action = element.get ("action")
|
||||
|
||||
if action in actions:
|
||||
label = actions[action]
|
||||
|
||||
if "_" in label:
|
||||
mnemonic = label[label.find ("_") + 1].upper ()
|
||||
|
||||
if mnemonic not in mnemonics:
|
||||
mnemonics[mnemonic] = []
|
||||
|
||||
mnemonics[mnemonic] += [action]
|
||||
|
||||
mnemonic_list = list (mnemonics.keys ())
|
||||
mnemonic_list.sort ()
|
||||
|
||||
for mnemonic in mnemonic_list:
|
||||
action_list = mnemonics[mnemonic]
|
||||
|
||||
if len (action_list) > 1:
|
||||
if found_clashes:
|
||||
print ()
|
||||
|
||||
if not found_clashes_in_menu:
|
||||
|
||||
if menu.tag == "menu":
|
||||
print ("In %s (%s):" % (menu.get ("action"),
|
||||
menu_path (menu)))
|
||||
elif menu.tag == "popup":
|
||||
print ("In %s:" % menu.get ("action"))
|
||||
else:
|
||||
print ("In top-level menu bar:")
|
||||
|
||||
found_clashes = True
|
||||
found_clashes_in_menu = True
|
||||
|
||||
print (" Mnemonic clash for '%s':" % mnemonic)
|
||||
|
||||
for action in action_list:
|
||||
print (" %s: %s" % (action, actions[action]))
|
||||
|
||||
exit (found_clashes)
|
||||
END
|
228
tools/module-dependencies.py
Normal file
228
tools/module-dependencies.py
Normal file
@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
"""
|
||||
module-dependencies.py -- PIKA library and core module dependency constructor
|
||||
Copyright (C) 2010 Martin Nordholts <martinn@src.gnome.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
|
||||
This program uses graphviz (you need PyGraphViz) to construct a graph
|
||||
with dependencies between PIKA library and core modules. Run it from
|
||||
the source root. Note that you'll either need the very latest
|
||||
PyGraphViz binding or use this hack in agraph.py:
|
||||
|
||||
--- agraph.py.orig 2010-01-04 16:07:46.000000000 +0100
|
||||
+++ agraph.py 2010-01-04 16:13:54.000000000 +0100
|
||||
@@ -1154,7 +1154,8 @@ class AGraph(object):
|
||||
raise IOError("".join(errors))
|
||||
|
||||
if len(errors)>0:
|
||||
- raise IOError("".join(errors))
|
||||
+ # Workaround exception throwing due to warning about cycles
|
||||
+ pass
|
||||
return "".join(data)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from __future__ import with_statement
|
||||
from sets import Set
|
||||
import os, re, pygraphviz
|
||||
|
||||
|
||||
|
||||
# First make a sanity check
|
||||
if not os.path.exists("app") or not os.path.exists("libpika"):
|
||||
print("Must be run in source root!")
|
||||
exit(-1);
|
||||
|
||||
|
||||
# This file lives in libpika and is used by many low-level
|
||||
# libs. Exclude it in the calculations so the graph become nicer
|
||||
ignored_interface_files = [
|
||||
"libpika/libpika-intl.h",
|
||||
]
|
||||
|
||||
# List of library modules
|
||||
libmodules = [
|
||||
"libpika",
|
||||
"libpikabase",
|
||||
"libpikacolor",
|
||||
"libpikaconfig",
|
||||
"libpikamath",
|
||||
"libpikamodule",
|
||||
"libpikathumb",
|
||||
"libpikawidgets",
|
||||
]
|
||||
|
||||
# List of app modules
|
||||
# XXX: Maybe group some of these together to simplify graph?
|
||||
appmodules = [
|
||||
"actions",
|
||||
"base",
|
||||
"composite",
|
||||
"config",
|
||||
"core",
|
||||
"dialogs",
|
||||
"display",
|
||||
"file",
|
||||
"gegl",
|
||||
"gui",
|
||||
"menus",
|
||||
"paint",
|
||||
"paint-funcs",
|
||||
"pdb",
|
||||
"plug-in",
|
||||
"tests",
|
||||
"text",
|
||||
"tools",
|
||||
"vectors",
|
||||
"widgets",
|
||||
"xcf",
|
||||
]
|
||||
|
||||
# Bootstrap modules, i.e. modules we assume exist even though we don't
|
||||
# have the code for them
|
||||
boostrap_modules = [
|
||||
[ "GLib", ["glib.h"] ],
|
||||
[ "GTK+", ["gtk/gtk.h"] ],
|
||||
[ "GEGL", ["gegl.h"] ],
|
||||
[ "Pango", ["pango/pango.h"] ],
|
||||
[ "Cairo", ["cairo.h"] ],
|
||||
]
|
||||
|
||||
##
|
||||
# Function to determine if a filename is for an interface file
|
||||
def is_interface_file(filename):
|
||||
return re.search("\.h$", filename)
|
||||
|
||||
##
|
||||
# Function to determine if a filename is for an implementation file,
|
||||
# i.e. a file that contains references to interface files
|
||||
def is_implementation_file(filename):
|
||||
return re.search("\.c$", filename)
|
||||
|
||||
##
|
||||
# Represents a software module. Think of it as a node in the
|
||||
# dependency graph
|
||||
class Module:
|
||||
def __init__(self, name, color, interface_files=[]):
|
||||
self.name = name
|
||||
self.color = color
|
||||
self.interface_files = Set(interface_files.__iter__())
|
||||
self.interface_file_dependencies = Set()
|
||||
self.dependencies = Set()
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
def get_color(self):
|
||||
return self.color
|
||||
|
||||
def get_interface_files(self):
|
||||
return self.interface_files
|
||||
|
||||
def get_interface_file_dependencies(self):
|
||||
return self.interface_file_dependencies
|
||||
|
||||
def get_dependencies(self):
|
||||
return self.dependencies
|
||||
|
||||
def add_module_dependency(self, module):
|
||||
if self != module:
|
||||
self.dependencies.add(module)
|
||||
|
||||
|
||||
# Represents a software module constructed from actual source code
|
||||
class CodeModule(Module):
|
||||
def __init__(self, path, color):
|
||||
Module.__init__(self, path, color)
|
||||
|
||||
all_files = os.listdir(path)
|
||||
|
||||
# Collect interfaces this module provides
|
||||
for interface_file in filter(is_interface_file, all_files):
|
||||
self.interface_files.add(os.path.join(path, interface_file))
|
||||
|
||||
# Collect dependencies to interfaces
|
||||
for filename in filter(is_implementation_file, all_files):
|
||||
with open(os.path.join(path, filename), 'r') as f:
|
||||
for line in f:
|
||||
m = re.search("#include +[\"<](.*)[\">]", line)
|
||||
if m:
|
||||
interface_file = m.group(1)
|
||||
# If the interface file appears to come from a core
|
||||
# module, prepend with "app/"
|
||||
m = re.search ("(.*)/.*", interface_file)
|
||||
if m:
|
||||
dirname = m.group(1)
|
||||
if appmodules.__contains__(dirname):
|
||||
interface_file = "app/" + interface_file
|
||||
|
||||
self.interface_file_dependencies.add(interface_file)
|
||||
|
||||
for ignored_interface_file in ignored_interface_files:
|
||||
self.interface_file_dependencies.discard(ignored_interface_file)
|
||||
|
||||
|
||||
|
||||
# Initialize the modules to use for the dependency analysis
|
||||
modules = Set()
|
||||
for bootstrap_module in boostrap_modules:
|
||||
modules.add(Module(bootstrap_module[0], 'lightblue', bootstrap_module[1]))
|
||||
for module_path in libmodules:
|
||||
modules.add(CodeModule(module_path, 'coral1'))
|
||||
for module_path in appmodules:
|
||||
modules.add(CodeModule("app/" + module_path, 'lawngreen'))
|
||||
|
||||
|
||||
# Map the interface files in the modules to the module that hosts them
|
||||
interface_file_to_module = {}
|
||||
for module in modules:
|
||||
for interface_file in module.get_interface_files():
|
||||
interface_file_to_module[interface_file] = module
|
||||
|
||||
# Figure out dependencies between modules
|
||||
unknown_interface_files = Set()
|
||||
for module in modules:
|
||||
interface_files = filter (is_interface_file, module.get_interface_file_dependencies())
|
||||
for interface_file in interface_files:
|
||||
if interface_file_to_module.has_key(interface_file):
|
||||
module.add_module_dependency(interface_file_to_module[interface_file])
|
||||
else:
|
||||
unknown_interface_files.add(interface_file)
|
||||
if False:
|
||||
print "Unknown interface files:", unknown_interface_files
|
||||
|
||||
# Construct a GraphViz graph from the modules
|
||||
dependency_graph = pygraphviz.AGraph(directed=True)
|
||||
for module in modules:
|
||||
dependency_graph.add_node(module, fillcolor=module.get_color(), style='filled')
|
||||
for module in modules:
|
||||
for depends_on in module.get_dependencies():
|
||||
dependency_graph.add_edge(module, depends_on)
|
||||
|
||||
# If module A depends on module B, and module B depends on module C, A
|
||||
# gets C implicitly. Perform a transitive reduction on the graph to
|
||||
# reflect this
|
||||
dependency_graph.tred()
|
||||
|
||||
# Write result
|
||||
if True:
|
||||
dependency_graph.draw("devel-docs/pika-module-dependencies.svg", prog="dot")
|
||||
else:
|
||||
dependency_graph.write("devel-docs/pika-module-dependencies.dot")
|
49
tools/performance-log-close-tags.py
Normal file
49
tools/performance-log-close-tags.py
Normal file
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-close-tags.py -- Closes open tags in PIKA performance logs
|
||||
Copyright (C) 2020 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-close-tags.py < infile > outfile
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
class OpenTagsTracker:
|
||||
open_tags = []
|
||||
|
||||
def start (self, tag, attrib):
|
||||
self.open_tags.append (tag)
|
||||
|
||||
def end (self, tag):
|
||||
self.open_tags.pop ()
|
||||
|
||||
# Read performance log from STDIN
|
||||
text = sys.stdin.buffer.read ()
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (text)
|
||||
|
||||
# Track open tags
|
||||
tracker = OpenTagsTracker ()
|
||||
|
||||
ElementTree.XMLParser (target = tracker).feed (text)
|
||||
|
||||
# Close remaining open tags
|
||||
for tag in reversed (tracker.open_tags):
|
||||
print ("</%s>" % tag)
|
62
tools/performance-log-coalesce.py
Normal file
62
tools/performance-log-coalesce.py
Normal file
@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-coalesce.py -- Coalesce PIKA performance log symbols, by
|
||||
filling-in missing base addresses
|
||||
Copyright (C) 2018 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-coalesce.py < infile > outfile
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
empty_element = ElementTree.Element ("")
|
||||
|
||||
# Read performance log from STDIN
|
||||
log = ElementTree.fromstring (sys.stdin.buffer.read ())
|
||||
|
||||
address_map = log.find ("address-map")
|
||||
|
||||
if address_map:
|
||||
addresses = []
|
||||
|
||||
# Create base addresses dictionary
|
||||
base_addresses = {}
|
||||
|
||||
for address in address_map.iterfind ("address"):
|
||||
symbol = address.find ("symbol").text
|
||||
source = address.find ("source").text
|
||||
base = address.find ("base").text
|
||||
|
||||
if symbol and source and not base:
|
||||
key = (symbol, source)
|
||||
value = int (address.get ("value"), 0)
|
||||
|
||||
base_addresses[key] = min (value, base_addresses.get (key, value))
|
||||
|
||||
addresses.append (address)
|
||||
|
||||
# Fill-in missing base addresses
|
||||
for address in addresses:
|
||||
symbol = address.find ("symbol").text
|
||||
source = address.find ("source").text
|
||||
|
||||
address.find ("base").text = hex (base_addresses[(symbol, source)])
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (ElementTree.tostring (log))
|
91
tools/performance-log-deduce.py
Normal file
91
tools/performance-log-deduce.py
Normal file
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-deduce.py -- Deduce PIKA performance log thread state
|
||||
Copyright (C) 2018 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-deduce.py < infile > outfile
|
||||
"""
|
||||
|
||||
DEDUCE_MIN_N_OCCURRENCES = 10
|
||||
DEDUCE_MIN_PERCENTAGE = 0.75
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
empty_element = ElementTree.Element ("")
|
||||
|
||||
# Read performance log from STDIN
|
||||
log = ElementTree.fromstring (sys.stdin.buffer.read ())
|
||||
|
||||
# Construct state histogram
|
||||
address_states = {}
|
||||
|
||||
for sample in (log.find ("samples") or empty_element).iterfind ("sample"):
|
||||
threads = (sample.find ("backtrace") or empty_element).iterfind ("thread")
|
||||
|
||||
for thread in threads:
|
||||
running = int (thread.get ("running"))
|
||||
|
||||
frame = thread.find ("frame")
|
||||
|
||||
if frame is not None:
|
||||
address = frame.get ("address")
|
||||
|
||||
states = address_states.setdefault (address, [0, 0])
|
||||
|
||||
states[running] += 1
|
||||
|
||||
# Find maximal states
|
||||
for address, states in list (address_states.items ()):
|
||||
n = sum (states)
|
||||
|
||||
if n >= DEDUCE_MIN_N_OCCURRENCES:
|
||||
state = 0
|
||||
m = states[0]
|
||||
|
||||
for i in range (1, len (states)):
|
||||
if states[i] > m:
|
||||
state = i
|
||||
m = states[i]
|
||||
|
||||
percentage = m / n
|
||||
|
||||
if percentage >= DEDUCE_MIN_PERCENTAGE:
|
||||
address_states[address] = state
|
||||
else:
|
||||
del address_states[address]
|
||||
else:
|
||||
del address_states[address]
|
||||
|
||||
# Replace thread states
|
||||
for sample in (log.find ("samples") or empty_element).iterfind ("sample"):
|
||||
threads = (sample.find ("backtrace") or empty_element).iterfind ("thread")
|
||||
|
||||
for thread in threads:
|
||||
frame = thread.find ("frame")
|
||||
|
||||
if frame is not None:
|
||||
address = frame.get ("address")
|
||||
|
||||
running = address_states.get (address, None)
|
||||
|
||||
if running is not None:
|
||||
thread.set ("running", str (running))
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (ElementTree.tostring (log))
|
107
tools/performance-log-expand.py
Normal file
107
tools/performance-log-expand.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-expand.py -- Delta-decodes PIKA performance logs
|
||||
Copyright (C) 2018 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-expand.py < infile > outfile
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
empty_element = ElementTree.Element ("")
|
||||
|
||||
# Read performance log from STDIN
|
||||
log = ElementTree.fromstring (sys.stdin.buffer.read ())
|
||||
|
||||
try:
|
||||
has_backtrace = bool (int (log.find ("params").find ("backtrace").text))
|
||||
except:
|
||||
has_backtrace = False
|
||||
|
||||
def expand_simple (element, last_values):
|
||||
last_values.update ({value.tag: value.text for value in element})
|
||||
|
||||
for value in list (element):
|
||||
element.remove (value)
|
||||
|
||||
for tag, text in last_values.items ():
|
||||
value = ElementTree.SubElement (element, tag)
|
||||
value.text = text
|
||||
value.tail = "\n"
|
||||
|
||||
# Expand samples
|
||||
last_vars = {}
|
||||
last_backtrace = {}
|
||||
|
||||
for sample in (log.find ("samples") or empty_element).iterfind ("sample"):
|
||||
# Expand variables
|
||||
vars = sample.find ("vars") or \
|
||||
ElementTree.SubElement (sample, "vars")
|
||||
|
||||
expand_simple (vars, last_vars)
|
||||
|
||||
# Expand backtrace
|
||||
if has_backtrace:
|
||||
backtrace = sample.find ("backtrace") or \
|
||||
ElementTree.SubElement (sample, "backtrace")
|
||||
|
||||
for thread in backtrace:
|
||||
id = thread.get ("id")
|
||||
head = thread.get ("head")
|
||||
tail = thread.get ("tail")
|
||||
attrib = dict (thread.attrib)
|
||||
frames = list (thread)
|
||||
|
||||
last_thread = last_backtrace.setdefault (id, [{}, []])
|
||||
last_frames = last_thread[1]
|
||||
|
||||
if head:
|
||||
frames = last_frames[:int (head)] + frames
|
||||
|
||||
del attrib["head"]
|
||||
|
||||
if tail:
|
||||
frames = frames + last_frames[-int (tail):]
|
||||
|
||||
del attrib["tail"]
|
||||
|
||||
last_thread[0] = attrib
|
||||
last_thread[1] = frames
|
||||
|
||||
if not frames and thread.text is None:
|
||||
del last_backtrace[id]
|
||||
|
||||
for thread in list (backtrace):
|
||||
backtrace.remove (thread)
|
||||
|
||||
for id, (attrib, frames) in last_backtrace.items ():
|
||||
thread = ElementTree.SubElement (backtrace, "thread", attrib)
|
||||
thread.text = "\n"
|
||||
thread.tail = "\n"
|
||||
|
||||
thread.extend (frames)
|
||||
|
||||
# Expand address map
|
||||
last_address = {}
|
||||
|
||||
for address in (log.find ("address-map") or empty_element).iterfind ("address"):
|
||||
expand_simple (address, last_address)
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (ElementTree.tostring (log))
|
54
tools/performance-log-progressive-coalesce.py
Normal file
54
tools/performance-log-progressive-coalesce.py
Normal file
@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-progressive-coalesce.py -- Coalesce address-maps in progressive
|
||||
PIKA performance logs
|
||||
Copyright (C) 2020 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-progressive-coalesce.py < infile > outfile
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
empty_element = ElementTree.Element ("")
|
||||
|
||||
# Read performance log from STDIN
|
||||
log = ElementTree.fromstring (sys.stdin.buffer.read ())
|
||||
|
||||
samples = log.find ("samples") or empty_element
|
||||
|
||||
address_map = log.find ("address-map")
|
||||
|
||||
if not address_map:
|
||||
address_map = ElementTree.Element ("address-map")
|
||||
|
||||
# Coalesce partial address maps
|
||||
for partial_address_map in samples.iterfind ("address-map"):
|
||||
for element in partial_address_map:
|
||||
address_map.append (element)
|
||||
|
||||
# Remove partial address maps
|
||||
for partial_address_map in samples.iterfind ("address-map"):
|
||||
samples.remove (partial_address_map)
|
||||
|
||||
# Add global address map
|
||||
if not log.find ("address-map") and len (address_map) > 0:
|
||||
log.append (address_map)
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (ElementTree.tostring (log))
|
55
tools/performance-log-resolve.py
Normal file
55
tools/performance-log-resolve.py
Normal file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
performance-log-resolve.py -- Resolve PIKA performance log backtrace symbols
|
||||
Copyright (C) 2018 Ell
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: performance-log-resolve.py < infile > outfile
|
||||
"""
|
||||
|
||||
from xml.etree import ElementTree
|
||||
import sys
|
||||
|
||||
empty_element = ElementTree.Element ("")
|
||||
|
||||
# Read performance log from STDIN
|
||||
log = ElementTree.fromstring (sys.stdin.buffer.read ())
|
||||
|
||||
address_map = log.find ("address-map")
|
||||
|
||||
if address_map:
|
||||
# Create address dictionary
|
||||
addresses = {}
|
||||
|
||||
for address in address_map.iterfind ("address"):
|
||||
addresses[address.get ("value")] = list (address)
|
||||
|
||||
# Resolve addresses in backtraces
|
||||
for sample in (log.find ("samples") or empty_element).iterfind ("sample"):
|
||||
for thread in sample.find ("backtrace") or ():
|
||||
for frame in thread:
|
||||
address = addresses.get (frame.get ("address"))
|
||||
|
||||
if address:
|
||||
frame.text = "\n"
|
||||
frame.extend (address)
|
||||
|
||||
# Remove address map
|
||||
log.remove (address_map)
|
||||
|
||||
# Write performance log to STDOUT
|
||||
sys.stdout.buffer.write (ElementTree.tostring (log))
|
39
tools/performance-log-viewer
Normal file
39
tools/performance-log-viewer
Normal file
@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
|
||||
# performance-log-viewer -- PIKA performance log viewer driver
|
||||
# Copyright (C) 2018 Ell
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
#
|
||||
# Usage: performance-log-viewer FILE
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 FILE"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tools_dir="$(dirname "$(command -v -- "$0")")"
|
||||
file="$1"
|
||||
|
||||
< "$file" || exit 1
|
||||
|
||||
< "$file" \
|
||||
"$tools_dir/performance-log-close-tags.py" | \
|
||||
"$tools_dir/performance-log-progressive-coalesce.py" | \
|
||||
"$tools_dir/performance-log-expand.py" | \
|
||||
"$tools_dir/performance-log-coalesce.py" | \
|
||||
"$tools_dir/performance-log-deduce.py" | \
|
||||
"$tools_dir/performance-log-viewer.py"
|
3662
tools/performance-log-viewer.py
Normal file
3662
tools/performance-log-viewer.py
Normal file
File diff suppressed because it is too large
Load Diff
113
tools/pika-debug-resume.c
Normal file
113
tools/pika-debug-resume.c
Normal file
@ -0,0 +1,113 @@
|
||||
/* based on pausep by Daniel Turini
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _WIN32_WINNT 0x0502
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <tlhelp32.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static BOOL
|
||||
resume_process (DWORD dwOwnerPID)
|
||||
{
|
||||
HANDLE hThreadSnap = NULL;
|
||||
BOOL bRet = FALSE;
|
||||
THREADENTRY32 te32 = { 0 };
|
||||
|
||||
hThreadSnap = CreateToolhelp32Snapshot (TH32CS_SNAPTHREAD, 0);
|
||||
if (hThreadSnap == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
te32.dwSize = sizeof (THREADENTRY32);
|
||||
|
||||
if (Thread32First (hThreadSnap, &te32))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (te32.th32OwnerProcessID == dwOwnerPID)
|
||||
{
|
||||
HANDLE hThread = OpenThread (THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);
|
||||
printf ("Resuming Thread: %u\n", (unsigned int) te32.th32ThreadID);
|
||||
ResumeThread (hThread);
|
||||
CloseHandle (hThread);
|
||||
}
|
||||
}
|
||||
while (Thread32Next (hThreadSnap, &te32));
|
||||
bRet = TRUE;
|
||||
}
|
||||
else
|
||||
bRet = FALSE;
|
||||
|
||||
CloseHandle (hThreadSnap);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
process_list (void)
|
||||
{
|
||||
HANDLE hProcessSnap = NULL;
|
||||
BOOL bRet = FALSE;
|
||||
PROCESSENTRY32 pe32 = {0};
|
||||
|
||||
hProcessSnap = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS, 0);
|
||||
|
||||
if (hProcessSnap == INVALID_HANDLE_VALUE)
|
||||
return FALSE;
|
||||
|
||||
pe32.dwSize = sizeof (PROCESSENTRY32);
|
||||
|
||||
if (Process32First (hProcessSnap, &pe32))
|
||||
{
|
||||
do
|
||||
{
|
||||
printf ("PID:\t%u\t%s\n",
|
||||
(unsigned int) pe32.th32ProcessID,
|
||||
pe32.szExeFile);
|
||||
}
|
||||
while (Process32Next (hProcessSnap, &pe32));
|
||||
bRet = TRUE;
|
||||
}
|
||||
else
|
||||
bRet = FALSE;
|
||||
|
||||
CloseHandle (hProcessSnap);
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char* argv[])
|
||||
{
|
||||
DWORD pid;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
process_list ();
|
||||
}
|
||||
else if (argc == 2)
|
||||
{
|
||||
pid = atoi (argv[1]);
|
||||
if (pid == 0)
|
||||
{
|
||||
printf ("invalid: %lu\n", pid);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("process: %lu\n", pid);
|
||||
resume_process (pid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Usage:\n"
|
||||
"resume : show processlist\n"
|
||||
"resume PID: resuming thread\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
579
tools/pika-mkenums
Normal file
579
tools/pika-mkenums
Normal file
@ -0,0 +1,579 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use warnings;
|
||||
|
||||
# This is pika-mkenums, a perl script based on glib-mkenums.
|
||||
# It can be used just like glib-mkenums but offers one extra
|
||||
# feature: The keyword "desc" is recognized in trigraphs and
|
||||
# allows to specify a literal description of the enum value.
|
||||
# This description is used to generate user interface elements
|
||||
# from the enumeration. To allow i18n of the description, the
|
||||
# value is by default put into the N_() macro.
|
||||
|
||||
use Text::ParseWords;
|
||||
use File::Basename;
|
||||
|
||||
# pika-mkenums
|
||||
# Information about the current enumeration
|
||||
my $flags; # Is enumeration a bitmask?
|
||||
my $option_lowercase_name; # A lower case name to use as part of the *_get_type() function, instead of the one that we guess.
|
||||
# For instance, when an enum uses abnormal capitalization and we can not guess where to put the underscores.
|
||||
my $seenbitshift; # Have we seen bitshift operators?
|
||||
my $enum_prefix; # Prefix for this enumeration
|
||||
my $enumname; # Name for this enumeration
|
||||
my $enumshort; # $enumname without prefix
|
||||
my $enumnick; # lower case version of $enumshort
|
||||
my $enumindex = 0; # Global enum counter
|
||||
my $firstenum = 1; # Is this the first enumeration per file?
|
||||
my @entries; # [ $name, $val ] for each entry
|
||||
|
||||
sub parse_trigraph {
|
||||
my $opts = shift;
|
||||
my @opts;
|
||||
|
||||
for $opt (quotewords(",", "true", $opts)) {
|
||||
$opt =~ s/^\s*//;
|
||||
$opt =~ s/\s*$//;
|
||||
my ($key,$val) = $opt =~ /(\w+)(?:=(.+))?/;
|
||||
defined $val or $val = 1;
|
||||
push @opts, $key, $val;
|
||||
}
|
||||
@opts;
|
||||
}
|
||||
|
||||
|
||||
sub parse_entries {
|
||||
my $file = shift;
|
||||
my $file_name = shift;
|
||||
my $looking_for_name = 0;
|
||||
|
||||
while (<$file>) {
|
||||
# read lines until we have no open comments
|
||||
while (m@/\*([^*]|\*(?!/))*$@) {
|
||||
my $new;
|
||||
defined ($new = <$file>) || die "Unmatched comment in $ARGV";
|
||||
$_ .= $new;
|
||||
}
|
||||
# strip comments w/o options
|
||||
s@/\*(?!<)
|
||||
([^*]+|\*(?!/))*
|
||||
\*/@@gx;
|
||||
|
||||
# strip newlines
|
||||
s@\n@ @;
|
||||
|
||||
# skip empty lines
|
||||
next if m@^\s*$@;
|
||||
|
||||
if ($looking_for_name) {
|
||||
if (/^\s*(\w+)/) {
|
||||
$enumname = $1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Handle include files
|
||||
if (/^\#include\s*<([^>]*)>/ ) {
|
||||
my $file= "../$1";
|
||||
open NEWFILE, $file or die "Cannot open include file $file: $!\n";
|
||||
|
||||
if (parse_entries (\*NEWFILE, $NEWFILE)) {
|
||||
return 1;
|
||||
} else {
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
if (/^\s*\}\s*(\w+)/) {
|
||||
$enumname = $1;
|
||||
$enumindex++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (/^\s*\}/) {
|
||||
$enumindex++;
|
||||
$looking_for_name = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
if (m@^\s*
|
||||
(\w+)\s* # name
|
||||
(?:=( # value
|
||||
\s*\w+\s*\(.*\)\s* # macro with multiple args
|
||||
| # OR
|
||||
(?:[^,/]|/(?!\*))* # anything but a comma or comment
|
||||
))?,?\s*
|
||||
(?:/\*< # options
|
||||
(([^*]|\*(?!/))*)
|
||||
>\s*\*/)?,?
|
||||
\s*$
|
||||
@x) {
|
||||
my ($name, $value, $options) = ($1,$2,$3);
|
||||
|
||||
if (!defined $flags && defined $value && $value =~ /<</) {
|
||||
$seenbitshift = 1;
|
||||
}
|
||||
|
||||
if (defined $options) {
|
||||
my %options = parse_trigraph($options);
|
||||
if (!defined $options{"skip"}) {
|
||||
push @entries, [ $name, $options{nick}, $options{desc}, $options{help}, $options{abbrev} ];
|
||||
}
|
||||
} else {
|
||||
push @entries, [ $name ];
|
||||
}
|
||||
|
||||
# skip remaining lines of multiline values
|
||||
do {
|
||||
if (m/}/) {
|
||||
redo;
|
||||
} elsif (m@,\s*(/\*.*?\*/\s*)*$@) {
|
||||
next;
|
||||
}
|
||||
} while (<$file>);
|
||||
|
||||
# failed to find end of value. bail
|
||||
die "$0: $file_name:$.: Unterminated enum, while processing `$name'\n";
|
||||
} elsif (m@^\s*\#@) {
|
||||
# ignore preprocessor directives
|
||||
} else {
|
||||
print STDERR "$0: $file_name:$.: Failed to parse `$_'\n";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub version {
|
||||
print STDERR "pika-mkenums based on glib-mkenums version glib-2.0\n";
|
||||
print STDERR "pika-mkenums comes with ABSOLUTELY NO WARRANTY.\n";
|
||||
print STDERR "You may redistribute copies of pika-mkenums under the terms\n";
|
||||
print STDERR "of the GNU General Public License which can be found in the\n";
|
||||
print STDERR "PIKA source package.";
|
||||
exit 0;
|
||||
}
|
||||
sub usage {
|
||||
print STDERR "Usage: pika-mkenums [options] [files...]\n";
|
||||
print STDERR " --fhead <text> output file header\n";
|
||||
print STDERR " --fprod <text> per input file production\n";
|
||||
print STDERR " --ftail <text> output file trailer\n";
|
||||
print STDERR " --eprod <text> per enum text (produced prior to value itarations)\n";
|
||||
print STDERR " --vhead <text> value header, produced before iterating over enum values\n";
|
||||
print STDERR " --vprod <text> value text, produced for each enum value\n";
|
||||
print STDERR " --vtail <text> value tail, produced after iterating over enum values\n";
|
||||
print STDERR " --dhead <text> description header, produced before iterating over enum value descriptions\n";
|
||||
print STDERR " --dprod <text> description text, produced for each enum value description\n";
|
||||
print STDERR " --dtail <text> description tail, produced after iterating over enum value descriptions\n";
|
||||
print STDERR " --comments <text> comment structure\n";
|
||||
print STDERR " -h, --help show this help message\n";
|
||||
print STDERR " -v, --version print version information\n";
|
||||
print STDERR "Production text substitutions:\n";
|
||||
print STDERR " \@EnumName\@ PrefixTheXEnum\n";
|
||||
print STDERR " \@enum_name\@ prefix_the_xenum\n";
|
||||
print STDERR " \@ENUMNAME\@ PREFIX_THE_XENUM\n";
|
||||
print STDERR " \@ENUMSHORT\@ THE_XENUM\n";
|
||||
print STDERR " \@enumnick\@ the_xenum\n";
|
||||
print STDERR " \@VALUENAME\@ PREFIX_THE_XVALUE\n";
|
||||
print STDERR " \@valuenick\@ the-xvalue\n";
|
||||
print STDERR " \@valuedesc\@ descriptions as defined in the header\n";
|
||||
print STDERR " \@valuehelp\@ help texts as defined in the header\n";
|
||||
print STDERR " \@valueabbrev\@ abbreviations as defined in the header\n";
|
||||
print STDERR " \@valueudesc\@ untranslated descriptions as defined in the header\n";
|
||||
print STDERR " \@valueuhelp\@ untranslated help texts as defined in the header\n";
|
||||
print STDERR " \@valueuabbrev\@ untranslated abbreviations as defined in the header\n";
|
||||
print STDERR " \@type\@ either enum or flags\n";
|
||||
print STDERR " \@Type\@ either Enum or Flags\n";
|
||||
print STDERR " \@TYPE\@ either ENUM or FLAGS\n";
|
||||
print STDERR " \@filename\@ name of current input file\n";
|
||||
print STDERR " \@basename\@ basename of current input file\n";
|
||||
print STDERR " \@if (...)\@ ... \@endif\@ conditional inclusion\n";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
# production variables:
|
||||
my $fhead = ""; # output file header
|
||||
my $fprod = ""; # per input file production
|
||||
my $ftail = ""; # output file trailer
|
||||
my $eprod = ""; # per enum text (produced prior to value itarations)
|
||||
my $vhead = ""; # value header, produced before iterating over enum values
|
||||
my $vprod = ""; # value text, produced for each enum value
|
||||
my $vtail = ""; # value tail, produced after iterating over enum values
|
||||
my $dhead = ""; # desc header, produced before iterating over enum values
|
||||
my $dprod = ""; # desc text, produced for each enum value
|
||||
my $dtail = ""; # desc tail, produced after iterating over enum values
|
||||
# other options
|
||||
my $comment_tmpl = "/* \@comment\@ */";
|
||||
|
||||
if (!defined $ARGV[0]) {
|
||||
usage;
|
||||
}
|
||||
while ($_ = $ARGV[0], /^-/) {
|
||||
shift;
|
||||
last if /^--$/;
|
||||
if (/^--fhead$/) { $fhead = $fhead . shift }
|
||||
elsif (/^--fprod$/) { $fprod = $fprod . shift }
|
||||
elsif (/^--ftail$/) { $ftail = $ftail . shift }
|
||||
elsif (/^--eprod$/) { $eprod = $eprod . shift }
|
||||
elsif (/^--vhead$/) { $vhead = $vhead . shift }
|
||||
elsif (/^--vprod$/) { $vprod = $vprod . shift }
|
||||
elsif (/^--vtail$/) { $vtail = $vtail . shift }
|
||||
elsif (/^--dhead$/) { $dhead = $dhead . shift }
|
||||
elsif (/^--dprod$/) { $dprod = $dprod . shift }
|
||||
elsif (/^--dtail$/) { $dtail = $dtail . shift }
|
||||
elsif (/^--comments$/) { $comment_tmpl = shift }
|
||||
elsif (/^--help$/ || /^-h$/) { usage; }
|
||||
elsif (/^--version$/ || /^-v$/) { version; }
|
||||
else { usage; }
|
||||
}
|
||||
|
||||
# put auto-generation comment
|
||||
{
|
||||
my $comment = $comment_tmpl;
|
||||
$comment =~ s/\@comment\@/Generated data (by pika-mkenums)/;
|
||||
print "\n" . $comment . "\n\n";
|
||||
}
|
||||
|
||||
if (length($fhead)) {
|
||||
my $prod = $fhead;
|
||||
|
||||
$prod =~ s/\@filename\@/$ARGV[0]/g;
|
||||
$prod =~ s/\@basename\@/basename($ARGV[0])/ge;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
while (<>) {
|
||||
if (eof) {
|
||||
close (ARGV); # reset line numbering
|
||||
$firstenum = 1; # Flag to print filename at next enum
|
||||
}
|
||||
|
||||
# read lines until we have no open comments
|
||||
while (m@/\*([^*]|\*(?!/))*$@) {
|
||||
my $new;
|
||||
defined ($new = <>) || die "Unmatched comment in $ARGV";
|
||||
$_ .= $new;
|
||||
}
|
||||
# strip comments w/o options
|
||||
s@/\*(?!<)
|
||||
([^*]+|\*(?!/))*
|
||||
\*/@@gx;
|
||||
|
||||
# ignore forward declarations
|
||||
next if /^\s*typedef\s+enum.*;/;
|
||||
|
||||
if (m@^\s*typedef\s+enum\s*
|
||||
(\{)?\s*
|
||||
(?:/\*<
|
||||
(([^*]|\*(?!/))*)
|
||||
>\s*\*/)?
|
||||
@x) {
|
||||
if (defined $2) {
|
||||
my %options = parse_trigraph ($2);
|
||||
next if defined $options{"skip"};
|
||||
$enum_prefix = $options{prefix};
|
||||
$flags = $options{flags};
|
||||
$option_lowercase_name = $options{lowercase_name};
|
||||
} else {
|
||||
$enum_prefix = undef;
|
||||
$flags = undef;
|
||||
$option_lowercase_name = undef;
|
||||
}
|
||||
# Didn't have trailing '{' look on next lines
|
||||
if (!defined $1) {
|
||||
while (<>) {
|
||||
if (eof) {
|
||||
die "Hit end of file while parsing enum in $ARGV";
|
||||
}
|
||||
if (s/^\s*\{//) {
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$seenbitshift = 0;
|
||||
|
||||
@entries = ();
|
||||
|
||||
# Now parse the entries
|
||||
parse_entries (\*ARGV, $ARGV);
|
||||
|
||||
# figure out if this was a flags or enums enumeration
|
||||
if (!defined $flags) {
|
||||
$flags = $seenbitshift;
|
||||
}
|
||||
|
||||
# Autogenerate a prefix
|
||||
if (!defined $enum_prefix) {
|
||||
for (@entries) {
|
||||
my $nick = $_->[1];
|
||||
if (!defined $nick) {
|
||||
my $name = $_->[0];
|
||||
if (defined $enum_prefix) {
|
||||
my $tmp = ~ ($name ^ $enum_prefix);
|
||||
($tmp) = $tmp =~ /(^\xff*)/;
|
||||
$enum_prefix = $enum_prefix & $tmp;
|
||||
} else {
|
||||
$enum_prefix = $name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!defined $enum_prefix) {
|
||||
$enum_prefix = "";
|
||||
} else {
|
||||
# Trim so that it ends in an underscore
|
||||
$enum_prefix =~ s/_[^_]*$/_/;
|
||||
}
|
||||
} else {
|
||||
# canonicalize user defined prefixes
|
||||
$enum_prefix = uc($enum_prefix);
|
||||
$enum_prefix =~ s/-/_/g;
|
||||
$enum_prefix =~ s/(.*)([^_])$/$1$2_/;
|
||||
}
|
||||
|
||||
|
||||
# enumname is e.g. GMatchType
|
||||
$enspace = $enumname;
|
||||
$enspace =~ s/^([A-Z][a-z]*).*$/$1/;
|
||||
|
||||
$enumshort = $enumname;
|
||||
$enumshort =~ s/^[A-Z][a-z]*//;
|
||||
$enumshort =~ s/([^A-Z])([A-Z])/$1_$2/g;
|
||||
$enumshort =~ s/([A-Z][A-Z])([A-Z][0-9a-z])/$1_$2/g;
|
||||
$enumshort = uc($enumshort);
|
||||
|
||||
$enumlong = uc($enspace) . "_" . $enumshort;
|
||||
$enumsym = lc($enspace) . "_" . lc($enumshort);
|
||||
|
||||
$enumnick = lc($enumshort);
|
||||
$enumnick =~ tr/_/-/;
|
||||
|
||||
for $entry (@entries) {
|
||||
my ($name,$nick,$desc,$help,$abbrev) = @{$entry};
|
||||
if (!defined $nick) {
|
||||
($nick = $name) =~ s/^$enum_prefix//;
|
||||
$nick =~ tr/_/-/;
|
||||
$nick = lc($nick);
|
||||
}
|
||||
if (!defined $desc) {
|
||||
$udesc = "\"$name\"";
|
||||
} else {
|
||||
$udesc = $desc;
|
||||
}
|
||||
if (!defined $desc) {
|
||||
$desc = "\"$name\"";
|
||||
} else {
|
||||
$desc = "NC_(\"$enumnick\", $desc)";
|
||||
}
|
||||
if (!defined $help) {
|
||||
$uhelp = "NULL";
|
||||
} else {
|
||||
$uhelp = $help;
|
||||
}
|
||||
if (!defined $help) {
|
||||
$help = "NULL";
|
||||
} else {
|
||||
$help = "N_($help)";
|
||||
}
|
||||
if (!defined $abbrev) {
|
||||
$uabbrev = "NULL";
|
||||
} else {
|
||||
$uabbrev = $abbrev;
|
||||
}
|
||||
if (!defined $abbrev) {
|
||||
$abbrev = "NULL";
|
||||
} else {
|
||||
$abbrev = "NC_(\"$enumnick\", $abbrev)";
|
||||
}
|
||||
@{$entry} = ($name, $nick, $desc, $help, $abbrev, $udesc, $uhelp, $uabbrev);
|
||||
}
|
||||
|
||||
|
||||
# Spit out the output
|
||||
|
||||
# The options might override the lower case name if it could
|
||||
# not be generated correctly:
|
||||
if (defined($option_lowercase_name)) {
|
||||
$enumsym = $option_lowercase_name;
|
||||
}
|
||||
|
||||
if ($firstenum) {
|
||||
$firstenum = 0;
|
||||
|
||||
if (length($fprod)) {
|
||||
my $prod = $fprod;
|
||||
|
||||
$prod =~ s/\@filename\@/$ARGV/g;
|
||||
$prod =~ s/\@basename\@/basename($ARGV)/ge;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (length($eprod)) {
|
||||
my $prod = $eprod;
|
||||
|
||||
$prod =~ s/\@enum_name\@/$enumsym/g;
|
||||
$prod =~ s/\@EnumName\@/$enumname/g;
|
||||
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
|
||||
$prod =~ s/\@enumnick\@/$enumnick/g;
|
||||
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
|
||||
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
if (length($vhead)) {
|
||||
my $prod = $vhead;
|
||||
|
||||
$prod =~ s/\@enum_name\@/$enumsym/g;
|
||||
$prod =~ s/\@EnumName\@/$enumname/g;
|
||||
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
|
||||
$prod =~ s/\@enumnick\@/$enumnick/g;
|
||||
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
|
||||
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
if (length($vprod)) {
|
||||
my $prod = $vprod;
|
||||
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
for (@entries) {
|
||||
my ($name,$nick,$desc,$help,$abbrev,$udesc,$uhelp,$uabbrev) = @{$_};
|
||||
my $tmp_prod = $prod;
|
||||
|
||||
$tmp_prod =~ s/\@VALUENAME\@/$name/g;
|
||||
$tmp_prod =~ s/\@valuenick\@/$nick/g;
|
||||
$tmp_prod =~ s/\@valuedesc\@/$desc/g;
|
||||
$tmp_prod =~ s/\@valuehelp\@/$help/g;
|
||||
$tmp_prod =~ s/\@valueabbrev\@/$abbrev/g;
|
||||
$tmp_prod =~ s/\@valueudesc\@/$udesc/g;
|
||||
$tmp_prod =~ s/\@valueuhelp\@/$uhelp/g;
|
||||
$tmp_prod =~ s/\@valueuabbrev\@/$uabbrev/g;
|
||||
if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $tmp_prod =~ s/\@Type\@/Flags/g; } else { $tmp_prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $tmp_prod =~ s/\@TYPE\@/FLAGS/g; } else { $tmp_prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$tmp_prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
|
||||
print "$tmp_prod\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (length($vtail)) {
|
||||
my $prod = $vtail;
|
||||
|
||||
$prod =~ s/\@enum_name\@/$enumsym/g;
|
||||
$prod =~ s/\@EnumName\@/$enumname/g;
|
||||
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
|
||||
$prod =~ s/\@enumnick\@/$enumnick/g;
|
||||
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
|
||||
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
if (length($dhead)) {
|
||||
my $prod = $dhead;
|
||||
|
||||
$prod =~ s/\@enum_name\@/$enumsym/g;
|
||||
$prod =~ s/\@EnumName\@/$enumname/g;
|
||||
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
|
||||
$prod =~ s/\@enumnick\@/$enumnick/g;
|
||||
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
|
||||
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
if (length($dprod)) {
|
||||
my $prod = $dprod;
|
||||
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
for (@entries) {
|
||||
my ($name,$nick,$desc,$help,$abbrev,$udesc,$uhelp,$uabbrev) = @{$_};
|
||||
my $tmp_prod = $prod;
|
||||
|
||||
$tmp_prod =~ s/\@VALUENAME\@/$name/g;
|
||||
$tmp_prod =~ s/\@valuenick\@/$nick/g;
|
||||
$tmp_prod =~ s/\@valuedesc\@/$desc/g;
|
||||
$tmp_prod =~ s/\@valuehelp\@/$help/g;
|
||||
$tmp_prod =~ s/\@valueabbrev\@/$abbrev/g;
|
||||
$tmp_prod =~ s/\@valueudesc\@/$udesc/g;
|
||||
$tmp_prod =~ s/\@valueuhelp\@/$uhelp/g;
|
||||
$tmp_prod =~ s/\@valueuabbrev\@/$uabbrev/g;
|
||||
if ($flags) { $tmp_prod =~ s/\@type\@/flags/g; } else { $tmp_prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $tmp_prod =~ s/\@Type\@/Flags/g; } else { $tmp_prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $tmp_prod =~ s/\@TYPE\@/FLAGS/g; } else { $tmp_prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$tmp_prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
|
||||
print "$tmp_prod\n";
|
||||
}
|
||||
}
|
||||
|
||||
if (length($dtail)) {
|
||||
my $prod = $dtail;
|
||||
|
||||
$prod =~ s/\@enum_name\@/$enumsym/g;
|
||||
$prod =~ s/\@EnumName\@/$enumname/g;
|
||||
$prod =~ s/\@ENUMSHORT\@/$enumshort/g;
|
||||
$prod =~ s/\@enumnick\@/$enumnick/g;
|
||||
$prod =~ s/\@ENUMNAME\@/$enumlong/g;
|
||||
if ($flags) { $prod =~ s/\@type\@/flags/g; } else { $prod =~ s/\@type\@/enum/g; }
|
||||
if ($flags) { $prod =~ s/\@Type\@/Flags/g; } else { $prod =~ s/\@Type\@/Enum/g; }
|
||||
if ($flags) { $prod =~ s/\@TYPE\@/FLAGS/g; } else { $prod =~ s/\@TYPE\@/ENUM/g; }
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (length($ftail)) {
|
||||
my $prod = $ftail;
|
||||
|
||||
$prod =~ s/\@filename\@/$ARGV/g;
|
||||
$prod =~ s/\@basename\@/basename($ARGV)/ge;
|
||||
$prod =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
$prod =~ s/\\a/\a/g; $prod =~ s/\\b/\b/g; $prod =~ s/\\t/\t/g; $prod =~ s/\\n/\n/g;
|
||||
$prod =~ s/\\f/\f/g; $prod =~ s/\\r/\r/g;
|
||||
|
||||
print "$prod\n";
|
||||
}
|
||||
|
||||
# put auto-generation comment
|
||||
{
|
||||
my $comment = $comment_tmpl;
|
||||
$comment =~ s/\@comment\@/Generated data ends here/;
|
||||
$comment =~ s/\@if (\((?>[^()]|(?1))*\))\@(.*?)\@endif\@/eval ($1) ? "$2" : ""/ges;
|
||||
print "\n" . $comment . "\n\n";
|
||||
}
|
443
tools/pika-test-clipboard.c
Normal file
443
tools/pika-test-clipboard.c
Normal file
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* pika-test-clipboard.c -- do clipboard things
|
||||
*
|
||||
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
|
||||
*
|
||||
* Use this code for whatever you like.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <glib/gstdio.h>
|
||||
#ifndef _O_BINARY
|
||||
#define _O_BINARY 0
|
||||
#endif
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libpikabase/pikabase.h"
|
||||
|
||||
|
||||
typedef struct _CopyData CopyData;
|
||||
|
||||
struct _CopyData
|
||||
{
|
||||
const gchar *filename;
|
||||
gboolean file_copied;
|
||||
GError *error;
|
||||
};
|
||||
|
||||
|
||||
static void test_clipboard_show_version (void) G_GNUC_NORETURN;
|
||||
static gboolean test_clipboard_parse_selection (const gchar *option_name,
|
||||
const gchar *value,
|
||||
gpointer data,
|
||||
GError **error);
|
||||
static gboolean test_clipboard_list_targets (GtkClipboard *clipboard);
|
||||
static gboolean test_clipboard_copy (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename);
|
||||
static gboolean test_clipboard_store (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename);
|
||||
static gboolean test_clipboard_paste (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename);
|
||||
static void test_clipboard_copy_callback (GtkClipboard *clipboard,
|
||||
GtkSelectionData *selection,
|
||||
guint info,
|
||||
gpointer data);
|
||||
|
||||
|
||||
static GdkAtom option_selection_type = GDK_SELECTION_CLIPBOARD;
|
||||
static gboolean option_list_targets = FALSE;
|
||||
static gchar *option_target = NULL;
|
||||
static gchar *option_copy_filename = NULL;
|
||||
static gchar *option_store_filename = NULL;
|
||||
static gchar *option_paste_filename = NULL;
|
||||
|
||||
static const GOptionEntry main_entries[] =
|
||||
{
|
||||
{
|
||||
"selection-type", 's', 0,
|
||||
G_OPTION_ARG_CALLBACK, test_clipboard_parse_selection,
|
||||
"Selection type (primary|secondary|clipboard)", "<type>"
|
||||
},
|
||||
{
|
||||
"list-targets", 'l', 0,
|
||||
G_OPTION_ARG_NONE, &option_list_targets,
|
||||
"List the targets offered by the clipboard", NULL
|
||||
},
|
||||
{
|
||||
"target", 't', 0,
|
||||
G_OPTION_ARG_STRING, &option_target,
|
||||
"The target format to copy or paste", "<target>"
|
||||
},
|
||||
{
|
||||
"copy", 'c', 0,
|
||||
G_OPTION_ARG_STRING, &option_copy_filename,
|
||||
"Copy <file> to clipboard", "<file>"
|
||||
},
|
||||
{
|
||||
"store", 'S', 0,
|
||||
G_OPTION_ARG_STRING, &option_store_filename,
|
||||
"Store <file> in the clipboard manager", "<file>"
|
||||
},
|
||||
{
|
||||
"paste", 'p', 0,
|
||||
G_OPTION_ARG_STRING, &option_paste_filename,
|
||||
"Paste clipboard into <file> ('-' pastes to STDOUT)", "<file>"
|
||||
},
|
||||
{
|
||||
"version", 'v', G_OPTION_FLAG_NO_ARG,
|
||||
G_OPTION_ARG_CALLBACK, test_clipboard_show_version,
|
||||
"Show version information and exit", NULL
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc,
|
||||
gchar *argv[])
|
||||
{
|
||||
GOptionContext *context;
|
||||
GtkClipboard *clipboard;
|
||||
GError *error = NULL;
|
||||
|
||||
context = g_option_context_new (NULL);
|
||||
g_option_context_add_main_entries (context, main_entries, NULL);
|
||||
g_option_context_add_group (context, gtk_get_option_group (TRUE));
|
||||
|
||||
if (! g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
g_printerr ("%s\n", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("%s\n",
|
||||
"Could not initialize the graphical user interface.\n"
|
||||
"Make sure a proper setup for your display environment "
|
||||
"exists.");
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
|
||||
option_selection_type);
|
||||
|
||||
if (! clipboard)
|
||||
g_error ("gtk_clipboard_get_for_display");
|
||||
|
||||
if (option_list_targets)
|
||||
{
|
||||
if (! test_clipboard_list_targets (clipboard))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ((option_copy_filename && option_paste_filename) ||
|
||||
(option_copy_filename && option_store_filename) ||
|
||||
(option_paste_filename && option_store_filename))
|
||||
{
|
||||
g_printerr ("Can't perform two operations at the same time\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (option_copy_filename)
|
||||
{
|
||||
if (! option_target)
|
||||
{
|
||||
g_printerr ("Usage: %s -t <target> -c <file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (! test_clipboard_copy (clipboard, option_target,
|
||||
option_copy_filename))
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (option_store_filename)
|
||||
{
|
||||
if (! option_target)
|
||||
{
|
||||
g_printerr ("Usage: %s -t <target> -S <file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (! test_clipboard_store (clipboard, option_target,
|
||||
option_store_filename))
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (option_paste_filename)
|
||||
{
|
||||
if (! option_target)
|
||||
{
|
||||
g_printerr ("Usage: %s -t <target> -p <file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (! test_clipboard_paste (clipboard, option_target,
|
||||
option_paste_filename))
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
test_clipboard_show_version (void)
|
||||
{
|
||||
g_print ("pika-test-clipboard (PIKA clipboard testbed) version %s\n",
|
||||
PIKA_VERSION);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_clipboard_parse_selection (const gchar *option_name,
|
||||
const gchar *value,
|
||||
gpointer data,
|
||||
GError **error)
|
||||
{
|
||||
if (! strcmp (value, "primary"))
|
||||
option_selection_type = GDK_SELECTION_PRIMARY;
|
||||
else if (! strcmp (value, "secondary"))
|
||||
option_selection_type = GDK_SELECTION_SECONDARY;
|
||||
else if (! strcmp (value, "clipboard"))
|
||||
option_selection_type = GDK_SELECTION_CLIPBOARD;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_clipboard_list_targets (GtkClipboard *clipboard)
|
||||
{
|
||||
GtkSelectionData *data;
|
||||
|
||||
data = gtk_clipboard_wait_for_contents (clipboard,
|
||||
gdk_atom_intern ("TARGETS",
|
||||
FALSE));
|
||||
if (data)
|
||||
{
|
||||
GdkAtom *targets;
|
||||
gint n_targets;
|
||||
gboolean success;
|
||||
|
||||
success = gtk_selection_data_get_targets (data, &targets, &n_targets);
|
||||
|
||||
gtk_selection_data_free (data);
|
||||
|
||||
if (success)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_targets; i++)
|
||||
g_print ("%s\n", gdk_atom_name (targets[i]));
|
||||
|
||||
g_free (targets);
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_clipboard_copy (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename)
|
||||
{
|
||||
GtkTargetEntry entry;
|
||||
CopyData data;
|
||||
|
||||
entry.target = g_strdup (target);
|
||||
entry.flags = 0;
|
||||
entry.info = 1;
|
||||
|
||||
data.filename = filename;
|
||||
data.file_copied = FALSE;
|
||||
data.error = NULL;
|
||||
|
||||
if (! gtk_clipboard_set_with_data (clipboard, &entry, 1,
|
||||
test_clipboard_copy_callback,
|
||||
NULL,
|
||||
&data))
|
||||
{
|
||||
g_printerr ("%s: gtk_clipboard_set_with_data() failed\n",
|
||||
g_get_prgname());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_main ();
|
||||
|
||||
if (! data.file_copied)
|
||||
{
|
||||
if (data.error)
|
||||
{
|
||||
g_printerr ("%s: copying failed: %s\n",
|
||||
g_get_prgname (), data.error->message);
|
||||
g_error_free (data.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: copying failed\n",
|
||||
g_get_prgname ());
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_clipboard_store (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename)
|
||||
{
|
||||
GtkTargetEntry entry;
|
||||
CopyData data;
|
||||
|
||||
entry.target = g_strdup (target);
|
||||
entry.flags = 0;
|
||||
entry.info = 1;
|
||||
|
||||
data.filename = filename;
|
||||
data.file_copied = FALSE;
|
||||
data.error = NULL;
|
||||
|
||||
if (! gtk_clipboard_set_with_data (clipboard, &entry, 1,
|
||||
test_clipboard_copy_callback,
|
||||
NULL,
|
||||
&data))
|
||||
{
|
||||
g_printerr ("%s: gtk_clipboard_set_with_data() failed\n",
|
||||
g_get_prgname ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_clipboard_set_can_store (clipboard, &entry, 1);
|
||||
gtk_clipboard_store (clipboard);
|
||||
|
||||
if (! data.file_copied)
|
||||
{
|
||||
if (data.error)
|
||||
{
|
||||
g_printerr ("%s: storing failed: %s\n",
|
||||
g_get_prgname (), data.error->message);
|
||||
g_error_free (data.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_printerr ("%s: could not contact clipboard manager\n",
|
||||
g_get_prgname ());
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
test_clipboard_paste (GtkClipboard *clipboard,
|
||||
const gchar *target,
|
||||
const gchar *filename)
|
||||
{
|
||||
GtkSelectionData *sel_data;
|
||||
|
||||
sel_data = gtk_clipboard_wait_for_contents (clipboard,
|
||||
gdk_atom_intern (target,
|
||||
FALSE));
|
||||
if (sel_data)
|
||||
{
|
||||
const guchar *data;
|
||||
gint length;
|
||||
gint fd;
|
||||
|
||||
if (! strcmp (filename, "-"))
|
||||
fd = 1;
|
||||
else
|
||||
fd = g_open (filename, O_WRONLY | O_CREAT | O_TRUNC | _O_BINARY, 0666);
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
g_printerr ("%s: open() filed: %s",
|
||||
g_get_prgname (), g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data = gtk_selection_data_get_data (sel_data);
|
||||
length = gtk_selection_data_get_length (sel_data);
|
||||
|
||||
if (write (fd, data, length) < length)
|
||||
{
|
||||
close (fd);
|
||||
g_printerr ("%s: write() failed: %s",
|
||||
g_get_prgname (), g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (close (fd) < 0)
|
||||
{
|
||||
g_printerr ("%s: close() failed: %s",
|
||||
g_get_prgname (), g_strerror (errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_selection_data_free (sel_data);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_clipboard_copy_callback (GtkClipboard *clipboard,
|
||||
GtkSelectionData *selection,
|
||||
guint info,
|
||||
gpointer data)
|
||||
{
|
||||
CopyData *copy_data = data;
|
||||
gchar *buf;
|
||||
gsize buf_size;
|
||||
|
||||
if (! g_file_get_contents (copy_data->filename, &buf, &buf_size,
|
||||
©_data->error))
|
||||
{
|
||||
if (! option_store_filename)
|
||||
gtk_main_quit ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_selection_data_set (selection,
|
||||
gtk_selection_data_get_target (selection),
|
||||
8, (guchar *) buf, buf_size);
|
||||
|
||||
g_free (buf);
|
||||
|
||||
copy_data->file_copied = TRUE;
|
||||
|
||||
g_print ("%s: data transfer in progress, hit <ctrl>+c when pasted...",
|
||||
G_STRFUNC);
|
||||
}
|
117
tools/pikapath2svg.py
Normal file
117
tools/pikapath2svg.py
Normal file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python2
|
||||
|
||||
import sys,re
|
||||
|
||||
"""
|
||||
pikapath2svg.py -- Converts Gimp-Paths to a SVG-File.
|
||||
Copyright (C) 2000 Simon Budig <simon@gimp.org>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
Usage: pikapath2svg.py [infile [outfile]]
|
||||
"""
|
||||
|
||||
|
||||
svgtemplate = """<?xml version="1.0" standalone="yes"?>
|
||||
<svg width="%d" height="%d">
|
||||
<g>
|
||||
<path id="%s" transform="translate (%d,%d)"
|
||||
style="stroke:#000000; stroke-width:1; fill:none"
|
||||
d="%s"/>
|
||||
</g>
|
||||
</svg>
|
||||
"""
|
||||
|
||||
emptysvgtemplate = """<?xml version="1.0" standalone="yes"?>
|
||||
<svg width="1" height="1">
|
||||
</svg>
|
||||
"""
|
||||
|
||||
|
||||
class Path:
|
||||
def __init__(self):
|
||||
self.name = ""
|
||||
self.svgpath = ""
|
||||
self.pikapoints = [[]]
|
||||
self.bounds = None
|
||||
|
||||
def readpikafile (self, filedesc):
|
||||
text = filedesc.readlines()
|
||||
for line in text:
|
||||
namematch = re.match ("Name: (.*)$", line)
|
||||
if namematch:
|
||||
path.name = namematch.group(1)
|
||||
pointmatch = re.match ("TYPE: (\d) X: (\d+) Y: (\d+)", line)
|
||||
if pointmatch:
|
||||
if pointmatch.group (1) == "3":
|
||||
path.pikapoints.append ([])
|
||||
(x, y) = map (int, pointmatch.groups()[1:])
|
||||
path.pikapoints[-1].append (map (int, pointmatch.groups()))
|
||||
if self.bounds:
|
||||
if self.bounds[0] > x: self.bounds[0] = x
|
||||
if self.bounds[1] > y: self.bounds[1] = y
|
||||
if self.bounds[2] < x: self.bounds[2] = x
|
||||
if self.bounds[3] < y: self.bounds[3] = y
|
||||
else:
|
||||
self.bounds = [x,y,x,y]
|
||||
|
||||
def makesvg (self):
|
||||
for path in self.pikapoints:
|
||||
if path:
|
||||
start = path[0]
|
||||
svg = "M %d %d " % tuple (start[1:])
|
||||
path = path[1:]
|
||||
while path:
|
||||
curve = path [0:3]
|
||||
path = path[3:]
|
||||
if len (curve) == 2:
|
||||
svg = svg + "C %d %d %d %d %d %d z " % tuple (
|
||||
tuple (curve [0][1:]) +
|
||||
tuple (curve [1][1:]) +
|
||||
tuple (start [1:]))
|
||||
if len (curve) == 3:
|
||||
svg = svg + "C %d %d %d %d %d %d " % tuple (
|
||||
tuple (curve [0][1:]) +
|
||||
tuple (curve [1][1:]) +
|
||||
tuple (curve [2][1:]))
|
||||
self.svgpath = self.svgpath + svg
|
||||
|
||||
def writesvgfile (self, outfile):
|
||||
if self.svgpath:
|
||||
svg = svgtemplate % (self.bounds[2]-self.bounds[0],
|
||||
self.bounds[3]-self.bounds[1],
|
||||
self.name,
|
||||
-self.bounds[0], -self.bounds[1],
|
||||
self.svgpath)
|
||||
else:
|
||||
svg = emptysvgtemplate
|
||||
outfile.write (svg)
|
||||
|
||||
|
||||
if len (sys.argv) > 1:
|
||||
infile = open (sys.argv[1])
|
||||
else:
|
||||
infile = sys.stdin
|
||||
|
||||
if len (sys.argv) > 2:
|
||||
outfile = open (sys.argv[2], "w")
|
||||
else:
|
||||
outfile = sys.stdout
|
||||
|
||||
|
||||
path = Path()
|
||||
path.readpikafile (infile)
|
||||
path.makesvg()
|
||||
path.writesvgfile (outfile)
|
1146
tools/pikatool.c
Normal file
1146
tools/pikatool.c
Normal file
File diff suppressed because it is too large
Load Diff
141
tools/release-stats.sh
Normal file
141
tools/release-stats.sh
Normal file
@ -0,0 +1,141 @@
|
||||
#!/bin/sh
|
||||
|
||||
############################################
|
||||
# Script gathering statistics on a release #
|
||||
############################################
|
||||
|
||||
#### Usage ####
|
||||
if [ "$#" -ne 2 -a "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 <PIKA_TAG_PREV> <PIKA_TAG_CUR>"
|
||||
echo
|
||||
echo " PIKA_TAG_PREV: last tag release or commit (non-included in stats)"
|
||||
echo " ex: PIKA_2_9_6"
|
||||
echo " PIKA_TAG_CUR: current tag release or commit (included in stats); ex: PIKA_2_9_8"
|
||||
echo " ex: PIKA_2_9_8."
|
||||
echo " Optional. If absent, statistics up to HEAD."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PREV=$1
|
||||
git --no-pager show $PREV >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "First tag is unknown: $PREV"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$#" = 2 ]; then
|
||||
CUR=$2
|
||||
git --no-pager show $CUR >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Second tag is unknown: $CUR"
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
CUR='HEAD'
|
||||
fi
|
||||
|
||||
echo "## PIKA contributions between $PREV and $CUR ##"
|
||||
echo
|
||||
|
||||
# Main stats:
|
||||
contribs=`git --no-pager shortlog -s -n $PREV..$CUR`
|
||||
contribs_n=`printf "$contribs" | wc -l`
|
||||
commits_n=`git log --oneline $PREV..$CUR | wc -l`
|
||||
|
||||
prev_date=`git log -1 --format=%ci $PREV`
|
||||
cur_date=`git log -1 --format=%ci $CUR`
|
||||
# I think this is not very portable, and may be a bash-specific syntax
|
||||
# for arithmetic operations. XXX
|
||||
days_n=$(( (`date -d "$cur_date" +%s` - `date -d "$prev_date" +%s`)/(60*60*24) ))
|
||||
commits_rate=$(( $commits_n / $days_n ))
|
||||
|
||||
echo "Start date: $prev_date - End date: $cur_date"
|
||||
echo "Between $PREV and $CUR, $contribs_n people contributed $commits_n commits to PIKA."
|
||||
echo "This is an average of $commits_rate commits a day."
|
||||
echo
|
||||
echo "Statistics on all files:" `git diff --shortstat $PREV..$CUR 2>/dev/null`
|
||||
echo
|
||||
echo "Total contributor list:"
|
||||
printf "$contribs"
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "## DEVELOPERS ##"
|
||||
echo
|
||||
|
||||
echo "Statistics on C files:" `git diff --shortstat $PREV..$CUR -- "*.[ch]" 2>/dev/null`
|
||||
echo
|
||||
echo "Core developers:"
|
||||
|
||||
git --no-pager shortlog -s -n $PREV..$CUR -- app/ "libpika*" pdb tools/pdbgen/
|
||||
|
||||
echo "Plugin and module developers:"
|
||||
|
||||
git --no-pager shortlog -s -n $PREV..$CUR -- plug-ins/ modules/
|
||||
|
||||
echo
|
||||
echo "## TRANSLATIONS ##"
|
||||
echo
|
||||
#git --no-pager log --stat $PREV..$CUR -- po* | grep "Updated\? .* translation"|sed "s/ *Updated\? \(.*\) translation.*/\\1/" | sort | uniq | paste -s -d, | sed 's/,/, /g'
|
||||
|
||||
i18n=`git --no-pager log --stat $PREV..$CUR -- po* | grep "Updated\? .* \(translation\|language\)"`
|
||||
i18n=`printf "$i18n" | sed "s/ *Updated\? \(.*\) \(translation\|language\).*/\\1/" | sort | uniq`
|
||||
i18n_n=`printf "$i18n" | wc -l`
|
||||
# It seems that if the last line has no newline, wc does not count it.
|
||||
# Add one line manually.
|
||||
i18n_n=$(( $i18n_n + 1 ))
|
||||
i18n_comma=`printf "$i18n" | paste -s -d, | sed 's/,/, /g'`
|
||||
|
||||
echo "$i18n_n translations were updated: $i18n_comma."
|
||||
echo
|
||||
|
||||
echo "Translators:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- "po*/*.po"
|
||||
|
||||
echo
|
||||
echo "## DESIGN ##"
|
||||
echo
|
||||
|
||||
new_icons=`git log --name-status $PREV..$CUR -- icons/*.svg icons/*.png 2>/dev/null|grep "^A\s"|sed 's%^.*/\([^/]*\)\..*$%\1%' | sort | uniq`
|
||||
icons_n=$((`printf "$new_icons" | wc -l` + 1))
|
||||
icons_comma=`printf "$new_icons" | paste -s -d, | sed 's/,/, /g'`
|
||||
|
||||
if [ "$icons_n" -lt 20 ]; then
|
||||
echo "$icons_n icons were added: $icons_comma"
|
||||
else
|
||||
echo "$icons_n icons were added (too many to list them all)."
|
||||
fi
|
||||
echo
|
||||
echo "Icon designers:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- "icons/*.svg" "icons/*.png"
|
||||
|
||||
echo "Theme designers:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- "themes/*/*.css" "themes/*/*png"
|
||||
|
||||
echo "Cursor creators:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- cursors/
|
||||
|
||||
echo "Resource creators:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- data/ etc/ desktop/ menus/
|
||||
|
||||
echo
|
||||
echo "## Documenters ##"
|
||||
echo
|
||||
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- docs/ devel-docs/ NEWS INSTALL.in "*README*" HACKING
|
||||
|
||||
echo
|
||||
echo "## Build maintainers ##"
|
||||
echo
|
||||
|
||||
echo "Core autotools build system:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- configure.ac "*/Makefile.am" "tools/"
|
||||
|
||||
echo "Meson build system:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- meson_options.txt "*/meson.build"
|
||||
|
||||
echo "Gitlab CI:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- .gitlab-ci.yml
|
||||
|
||||
echo "Binary builds:"
|
||||
git --no-pager shortlog -sn $PREV..$CUR -- build/
|
Reference in New Issue
Block a user