Compare commits
9 commits
437f8af8cf
...
3431309511
Author | SHA1 | Date | |
---|---|---|---|
chayleaf | 3431309511 | ||
chayleaf | 4b560281bd | ||
chayleaf | 63eab7c843 | ||
chayleaf | 03332873d2 | ||
chayleaf | d7a732d78a | ||
chayleaf | 0b7fdd43cb | ||
chayleaf | b0b136b6d7 | ||
chayleaf | 8b6a6035c6 | ||
chayleaf | 5ef36a7b93 |
52
flake.lock
52
flake.lock
|
@ -143,6 +143,27 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"crane_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"unbound-rust-mod",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1722960479,
|
||||
"narHash": "sha256-NhCkJJQhD5GUib8zN9JrmYGMwt4lCRp6ZVNzIiYCl0Y=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "4c6c77920b8d44cd6660c1621dea6b3fc4b4c4f4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"disko": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
@ -324,16 +345,15 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1714645000,
|
||||
"narHash": "sha256-RelIgcYWJnUdE96Hjh8gR6wmsNgLc1LHDZY5VtdR6Eo=",
|
||||
"lastModified": 1723599998,
|
||||
"narHash": "sha256-9a/Dq7WUhP35WrpqXUpDBsnKoKASsYB8FQjIeVlghm4=",
|
||||
"owner": "chayleaf",
|
||||
"repo": "home-manager",
|
||||
"rev": "2a477b78f5e95a0b8ed741786524ca0fbfe0c230",
|
||||
"rev": "c29f1c444bbfe3cfa22e347923fe04245030bcda",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "chayleaf",
|
||||
"ref": "librewolf",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
|
@ -757,7 +777,8 @@
|
|||
"notnft": "notnft",
|
||||
"nur": "nur",
|
||||
"osu-wine": "osu-wine",
|
||||
"rust-overlay": "rust-overlay"
|
||||
"rust-overlay": "rust-overlay",
|
||||
"unbound-rust-mod": "unbound-rust-mod"
|
||||
}
|
||||
},
|
||||
"rust-overlay": {
|
||||
|
@ -908,6 +929,27 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"unbound-rust-mod": {
|
||||
"inputs": {
|
||||
"crane": "crane_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723550937,
|
||||
"narHash": "sha256-5gEXPy9qIrNi0nPk3D1ctVxh5Ndfrhyu+02R6BIcnHQ=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "e0f642180056f351fd712f2b4f3149fd9f02367f",
|
||||
"revCount": 24,
|
||||
"type": "git",
|
||||
"url": "https://git.pavluk.org/chayleaf/unbound-rust-mod.git"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.pavluk.org/chayleaf/unbound-rust-mod.git"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
|
|
22
flake.nix
22
flake.nix
|
@ -29,7 +29,7 @@
|
|||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
home-manager = {
|
||||
url = "github:chayleaf/home-manager/librewolf";
|
||||
url = "github:chayleaf/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nix-gaming = {
|
||||
|
@ -52,6 +52,10 @@
|
|||
url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
unbound-rust-mod = {
|
||||
url = "git+https://git.pavluk.org/chayleaf/unbound-rust-mod.git";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
flake-compat = {
|
||||
url = "github:edolstra/flake-compat";
|
||||
flake = false;
|
||||
|
@ -69,6 +73,7 @@
|
|||
# nixos-router = true;
|
||||
# notnft = true;
|
||||
# nixpkgs = true;
|
||||
# unbound-rust-mod = true;
|
||||
};
|
||||
# IRL-related stuff I'd rather not put into git
|
||||
priv =
|
||||
|
@ -197,9 +202,11 @@
|
|||
hardware = inputs.nixos-hardware.nixosModules;
|
||||
} // args.specialArgs or { };
|
||||
modules = [
|
||||
{ _module.args = {
|
||||
pkgs-kernel = import inputs.nixpkgs-kernel { inherit (args) system; overlays = all-overlays; };
|
||||
}; }
|
||||
({ config, ... }: {
|
||||
_module.args = {
|
||||
pkgs-kernel = import inputs.nixpkgs-kernel { inherit (args) system; overlays = all-overlays ++ config.nixpkgs.overlays; };
|
||||
};
|
||||
})
|
||||
(getPrivSys hostname)
|
||||
{ networking.hostName = lib.mkDefault hostname;
|
||||
nixpkgs.overlays = all-overlays; }
|
||||
|
@ -238,7 +245,11 @@
|
|||
extraSpecialArgs = { inherit inputs; };
|
||||
modules = [
|
||||
./home/hosts/remote.nix
|
||||
({ pkgs, ... }: { home.file.hysteria.source = pkgs.hysteria; })
|
||||
({ pkgs, ... }: {
|
||||
home.file.hysteria.source = pkgs.hysteria;
|
||||
home.file.shadowsocks-libev.source = pkgs.shadowsocks-libev;
|
||||
home.file.shadowsocks-rust.source = pkgs.shadowsocks-rust;
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@ -261,7 +272,6 @@
|
|||
++ [
|
||||
(getPrivUser hostname user)
|
||||
({ pkgs, lib, ... }: {
|
||||
nixpkgs.overlays = all-overlays;
|
||||
nix.package = lib.mkDefault pkgs.nixForNixPlugins;
|
||||
})
|
||||
];
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
lalrpop
|
||||
tio
|
||||
tdesktop
|
||||
osu-wine
|
||||
];
|
||||
xdg.configFile."looking-glass/client.ini".text = ''
|
||||
[app]
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
{
|
||||
imports = [ ./gui.nix ];
|
||||
|
||||
programs.firefox = {
|
||||
programs.librewolf = {
|
||||
enable = true;
|
||||
package = pkgs.wrapFirefox pkgs.librewolf-unwrapped {
|
||||
inherit (pkgs.librewolf-unwrapped) extraPrefsFiles extraPoliciesFiles;
|
||||
|
@ -15,6 +15,17 @@
|
|||
libName = "librewolf";
|
||||
nativeMessagingHosts = with pkgs; [ keepassxc ];
|
||||
};
|
||||
profiles.other.id = 1;
|
||||
profiles.other.bookmarks = [{
|
||||
name = "bookmarklets";
|
||||
toolbar = true;
|
||||
bookmarks = [
|
||||
{
|
||||
name = "example.com";
|
||||
url = "https://example.com";
|
||||
}
|
||||
];
|
||||
}];
|
||||
profiles.chayleaf = lib.mkMerge [
|
||||
{
|
||||
extensions = (with config.nur.repos.rycee.firefox-addons; [
|
||||
|
|
|
@ -172,11 +172,11 @@ commonConfig = {
|
|||
names = [ "Noto Sans Mono" "Symbols Nerd Font Mono" ];
|
||||
size = 16.0;
|
||||
};
|
||||
gaps = {
|
||||
smartBorders = "on";
|
||||
smartGaps = true;
|
||||
inner = 10;
|
||||
};
|
||||
# gaps = {
|
||||
# smartBorders = "on";
|
||||
# smartGaps = true;
|
||||
# inner = 10;
|
||||
# };
|
||||
window.hideEdgeBorders = "smart";
|
||||
workspaceAutoBackAndForth = true;
|
||||
};
|
||||
|
@ -259,15 +259,25 @@ in
|
|||
'';
|
||||
wayland.windowManager.sway = {
|
||||
wrapperFeatures.gtk = true;
|
||||
package = pkgs.sway-unwrapped.overrideAttrs (old: {
|
||||
patches = old.patches or [] ++ [
|
||||
./sway.patch
|
||||
/*(pkgs.fetchpatch {
|
||||
url = "https://patch-diff.githubusercontent.com/raw/swaywm/sway/pull/6920.patch";
|
||||
sha256 = "sha256-XgkysduhHbmprE334yeL65txpK0HNXeCmgCZMxpwsgU=";
|
||||
})*/
|
||||
];
|
||||
});
|
||||
package = let
|
||||
cfg = config.wayland.windowManager.sway;
|
||||
in pkgs.sway.override {
|
||||
sway-unwrapped = pkgs.sway-unwrapped.overrideAttrs (old: {
|
||||
patches = old.patches or [] ++ [
|
||||
../../pkgs/sway/allow-other.patch
|
||||
/*(pkgs.fetchpatch {
|
||||
url = "https://patch-diff.githubusercontent.com/raw/swaywm/sway/pull/6920.patch";
|
||||
sha256 = "sha256-XgkysduhHbmprE334yeL65txpK0HNXeCmgCZMxpwsgU=";
|
||||
})*/
|
||||
] ++ lib.optionals config.phone.enable
|
||||
(map
|
||||
(x: ../../pkgs/sway/${x})
|
||||
(builtins.filter (lib.hasInfix "-mobile-") (builtins.attrNames (builtins.readDir ../../pkgs/sway))));
|
||||
});
|
||||
inherit (cfg) extraSessionCommands extraOptions;
|
||||
withBaseWrapper = cfg.wrapperFeatures.base;
|
||||
withGtkWrapper = cfg.wrapperFeatures.gtk;
|
||||
};
|
||||
extraConfig = ''
|
||||
title_align center
|
||||
'';
|
||||
|
@ -297,6 +307,11 @@ in
|
|||
app_id = "^org.keepassxc.KeePassXC$";
|
||||
title = "^KeePassXC - (?:Browser |ブラウザーの)?(?:Access Request|アクセス要求)$";
|
||||
}; }
|
||||
{ command = "floating on; border normal";
|
||||
criteria = {
|
||||
class = "ghidra-Ghidra";
|
||||
title = "\\[CodeBrowser.*\\]$";
|
||||
}; }
|
||||
]; };
|
||||
assigns = {
|
||||
"2" = [
|
||||
|
|
|
@ -19,8 +19,10 @@
|
|||
sha256 = "sha256-zH4hbQ8+9TYRVW/XYqmAVsi0vsSPn1LPqXxr0gi0j1E=";
|
||||
};
|
||||
});*/
|
||||
settings = lib.toList {
|
||||
layer = "top";
|
||||
settings = let
|
||||
layer = if config.phone.enable then "overlay" else "top";
|
||||
in lib.toList {
|
||||
inherit layer;
|
||||
position = "top";
|
||||
ipc = true;
|
||||
height = 40;
|
||||
|
@ -151,7 +153,7 @@
|
|||
};
|
||||
} ++ lib.optionals config.phone.enable [
|
||||
{
|
||||
layer = "top";
|
||||
inherit layer;
|
||||
position = "top";
|
||||
ipc = true;
|
||||
height = 40;
|
||||
|
@ -168,7 +170,7 @@
|
|||
modules-right = [ "clock" ];
|
||||
}
|
||||
{
|
||||
layer = "top";
|
||||
inherit layer;
|
||||
position = "bottom";
|
||||
ipc = true;
|
||||
height = 80;
|
||||
|
|
|
@ -22,6 +22,8 @@ in
|
|||
inherit (inputs.osu-wine.packages.${pkgs.system}) osu-wine;
|
||||
matrix-appservice-discord = pkgs.callPackage ./matrix-appservice-discord { inherit (pkgs) matrix-appservice-discord; };
|
||||
|
||||
krita = pkgs.callPackage ./krita { inherit (pkgs) krita; };
|
||||
|
||||
openssh = pkgs.openssh.overrideAttrs (old: rec {
|
||||
version = "9.8p1";
|
||||
src = pkgs.fetchurl {
|
||||
|
@ -30,6 +32,11 @@ in
|
|||
};
|
||||
});
|
||||
|
||||
inherit (inputs.unbound-rust-mod.packages.${pkgs.system}) unbound-mod;
|
||||
unbound-full = pkgs.unbound-full.overrideAttrs (old: {
|
||||
configureFlags = old.configureFlags ++ [ "--with-dynlibmodule" ];
|
||||
});
|
||||
|
||||
buffyboard = pkgs.callPackage ./buffyboard { };
|
||||
clang-tools_latest = pkgs.clang-tools_16;
|
||||
clang_latest = pkgs.clang_16;
|
||||
|
@ -39,8 +46,12 @@ in
|
|||
gimp = callPackage ./gimp { inherit (pkgs) gimp; };
|
||||
home-daemon = callPackage ./home-daemon { };
|
||||
# pin version
|
||||
looking-glass-client = pkgs.looking-glass-client.overrideAttrs (old: {
|
||||
looking-glass-client = pkgs.looking-glass-client.overrideAttrs (old: rec {
|
||||
version = "B6";
|
||||
postUnpack = ''
|
||||
echo ${src.rev} > source/VERSION
|
||||
export sourceRoot="source/client"
|
||||
'';
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "gnif";
|
||||
repo = "LookingGlass";
|
||||
|
@ -50,8 +61,7 @@ in
|
|||
};
|
||||
patches = [ ];
|
||||
});
|
||||
kvmfrOverlay = kvmfr: kvmfr.overrideAttrs (old: {
|
||||
inherit (pkgs'.looking-glass-client) version src;
|
||||
kvmfrOverlay = kvmfr: (kvmfr.override { inherit (pkgs') looking-glass-client; }).overrideAttrs (old: {
|
||||
patches = [ ./looking-glass.patch ];
|
||||
});
|
||||
mobile-config-firefox = callPackage ./mobile-config-firefox { };
|
||||
|
|
12
pkgs/krita/default.nix
Normal file
12
pkgs/krita/default.nix
Normal file
|
@ -0,0 +1,12 @@
|
|||
{ krita, python3Packages }:
|
||||
|
||||
(krita.override {
|
||||
unwrapped = krita.unwrapped.overrideAttrs (old: { patches = old.patches or [] ++ [
|
||||
./painting-api.patch
|
||||
./fix-painting-api-crashes.patch
|
||||
./painting-api-options.patch
|
||||
./painting-api-pressure.patch
|
||||
]; });
|
||||
}).overrideAttrs (old: {
|
||||
buildInputs = old.buildInputs ++ [ python3Packages.requests ];
|
||||
})
|
145
pkgs/krita/fix-painting-api-crashes.patch
Normal file
145
pkgs/krita/fix-painting-api-crashes.patch
Normal file
|
@ -0,0 +1,145 @@
|
|||
diff --git a/libs/libkis/Node.cpp b/libs/libkis/Node.cpp
|
||||
index 84f24d3..0e2370e 100644
|
||||
--- a/libs/libkis/Node.cpp
|
||||
+++ b/libs/libkis/Node.cpp
|
||||
@@ -76,6 +76,8 @@
|
||||
#include "KisAsynchronousStrokeUpdateHelper.h"
|
||||
#include "kis_stroke_strategy.h"
|
||||
#include "PaintingResources.h"
|
||||
+#include "KisMainWindow.h"
|
||||
+#include "kis_canvas2.h"
|
||||
|
||||
|
||||
struct Node::Private {
|
||||
@@ -833,8 +835,48 @@ KisNodeSP Node::node() const
|
||||
return d->node;
|
||||
}
|
||||
|
||||
+QString Node::paintAbility()
|
||||
+{
|
||||
+ // Taken from KisTool:nodePaintAbility().
|
||||
+ KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow();
|
||||
+ KisCanvas2 *canvas = mainWindow->activeView()->canvasBase();
|
||||
+ if (canvas->resourceManager()->resource(KoCanvasResource::CurrentPaintOpPreset).isNull()) {
|
||||
+ return "UNPAINTABLE";
|
||||
+ }
|
||||
+
|
||||
+ if (!d->node) {
|
||||
+ return "UNPAINTABLE";
|
||||
+ }
|
||||
+
|
||||
+ if (d->node->inherits("KisShapeLayer")) {
|
||||
+ return "VECTOR";
|
||||
+ }
|
||||
+ if (d->node->inherits("KisCloneLayer")) {
|
||||
+ return "CLONE";
|
||||
+ }
|
||||
+ if (d->node->paintDevice()) {
|
||||
+
|
||||
+ KisPaintOpPresetSP currentPaintOpPreset = canvas->resourceManager()->resource(KoCanvasResource::CurrentPaintOpPreset).value<KisPaintOpPresetSP>();
|
||||
+ if (currentPaintOpPreset->paintOp().id() == "mypaintbrush") {
|
||||
+ const KoColorSpace *colorSpace = d->node->paintDevice()->colorSpace();
|
||||
+ if (colorSpace->colorModelId() != RGBAColorModelID) {
|
||||
+ return "MYPAINTBRUSH_UNPAINTABLE";
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return "PAINT";
|
||||
+ }
|
||||
+
|
||||
+ return "UNPAINTABLE";
|
||||
+}
|
||||
+
|
||||
void Node::paintLine(const QPointF pointOne, const QPointF pointTwo)
|
||||
{
|
||||
+ if (paintAbility() != "PAINT") {
|
||||
+ dbgScript << "Script attempted to use Node::paintLine() on an unpaintable node, ignoring.";
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
KisPaintInformation pointOneInfo;
|
||||
pointOneInfo.setPressure(1.0);
|
||||
pointOneInfo.setPos(pointOne);
|
||||
@@ -850,6 +892,11 @@ void Node::paintLine(const QPointF pointOne, const QPointF pointTwo)
|
||||
|
||||
void Node::paintRectangle(const QRectF &rect)
|
||||
{
|
||||
+ if (paintAbility() != "PAINT") {
|
||||
+ dbgScript << "Script attempted to use Node::paintRectangle() on an unpaintable node, ignoring.";
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// reference class where this stuff is being done. Maybe can use the "facade" like that does for setup?
|
||||
// void KisFigurePaintingToolHelper::paintRect(const QRectF &rect)
|
||||
|
||||
@@ -860,6 +907,11 @@ void Node::paintRectangle(const QRectF &rect)
|
||||
|
||||
void Node::paintPolygon(const QList<QPointF> listPoint)
|
||||
{
|
||||
+ if (paintAbility() != "PAINT") {
|
||||
+ dbgScript << "Script attempted to use Node::paintPolygon() on an unpaintable node, ignoring.";
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// strategy needs points in vPointF format
|
||||
QVector<QPointF> points = points.fromList(listPoint);
|
||||
KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
@@ -869,6 +921,11 @@ void Node::paintPolygon(const QList<QPointF> listPoint)
|
||||
|
||||
void Node::paintEllipse(const QRectF &rect)
|
||||
{
|
||||
+ if (paintAbility() != "PAINT") {
|
||||
+ dbgScript << "Script attempted to use Node::paintEllipse() on an unpaintable node, ignoring.";
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
helper.paintEllipse(rect);
|
||||
}
|
||||
@@ -876,6 +933,11 @@ void Node::paintEllipse(const QRectF &rect)
|
||||
|
||||
void Node::paintPath(const QPainterPath &path)
|
||||
{
|
||||
+ if (paintAbility() != "PAINT") {
|
||||
+ dbgScript << "Script attempted to use Node::paintPath() on an unpaintable node, ignoring.";
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
helper.paintPainterPath(path);
|
||||
}
|
||||
diff --git a/libs/libkis/Node.h b/libs/libkis/Node.h
|
||||
index 10daba4..89a6f40 100644
|
||||
--- a/libs/libkis/Node.h
|
||||
+++ b/libs/libkis/Node.h
|
||||
@@ -601,6 +601,18 @@ public Q_SLOTS:
|
||||
*/
|
||||
void paintPath(const QPainterPath &path);
|
||||
|
||||
+ /**
|
||||
+ * @brief paintAbility can be used to determine whether this node can be painted on with the current brush preset.
|
||||
+ * @return QString, one of the following:
|
||||
+ * <ul>
|
||||
+ * <li>VECTOR - This node is vector-based.</li>
|
||||
+ * <li>CLONE - This node is a Clone Layer.</li>
|
||||
+ * <li>PAINT - This node is paintable by the current brush preset.</li>
|
||||
+ * <li>UNPAINTABLE - This node is not paintable, or a null preset is somehow selected./li>
|
||||
+ * <li>MYPAINTBRUSH_UNPAINTABLE - This node's non-RGBA colorspace cannot be painted on by the currently selected MyPaint brush.</li>
|
||||
+ */
|
||||
+ QString paintAbility();
|
||||
+
|
||||
private:
|
||||
|
||||
friend class Filter;
|
||||
diff --git a/plugins/extensions/pykrita/sip/krita/Node.sip b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
index cbcef0f..6270bd9 100644
|
||||
--- a/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
+++ b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
@@ -75,6 +75,7 @@ public Q_SLOTS:
|
||||
void paintPolygon(const QList<QPointF> points);
|
||||
void paintEllipse(const QRectF &rect);
|
||||
void paintPath(const QPainterPath &path);
|
||||
+ QString paintAbility();
|
||||
Q_SIGNALS:
|
||||
private:
|
||||
};
|
332
pkgs/krita/painting-api-options.patch
Normal file
332
pkgs/krita/painting-api-options.patch
Normal file
|
@ -0,0 +1,332 @@
|
|||
diff --git a/libs/libkis/Node.cpp b/libs/libkis/Node.cpp
|
||||
index 0e2370e..3eed4ea 100644
|
||||
--- a/libs/libkis/Node.cpp
|
||||
+++ b/libs/libkis/Node.cpp
|
||||
@@ -870,7 +870,7 @@ QString Node::paintAbility()
|
||||
return "UNPAINTABLE";
|
||||
}
|
||||
|
||||
-void Node::paintLine(const QPointF pointOne, const QPointF pointTwo)
|
||||
+void Node::paintLine(const QPointF pointOne, const QPointF pointTwo, const QString strokeStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintLine() on an unpaintable node, ignoring.";
|
||||
@@ -885,12 +885,12 @@ void Node::paintLine(const QPointF pointOne, const QPointF pointTwo)
|
||||
pointTwoInfo.setPressure(1.0);
|
||||
pointTwoInfo.setPos(pointTwo);
|
||||
|
||||
- KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle);
|
||||
helper.paintLine(pointOneInfo, pointTwoInfo);
|
||||
}
|
||||
|
||||
|
||||
-void Node::paintRectangle(const QRectF &rect)
|
||||
+void Node::paintRectangle(const QRectF &rect, const QString strokeStyle, const QString fillStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintRectangle() on an unpaintable node, ignoring.";
|
||||
@@ -900,12 +900,12 @@ void Node::paintRectangle(const QRectF &rect)
|
||||
// reference class where this stuff is being done. Maybe can use the "facade" like that does for setup?
|
||||
// void KisFigurePaintingToolHelper::paintRect(const QRectF &rect)
|
||||
|
||||
- KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle, fillStyle);
|
||||
helper.paintRect(rect);
|
||||
}
|
||||
|
||||
|
||||
-void Node::paintPolygon(const QList<QPointF> listPoint)
|
||||
+void Node::paintPolygon(const QList<QPointF> listPoint, const QString strokeStyle, const QString fillStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintPolygon() on an unpaintable node, ignoring.";
|
||||
@@ -914,30 +914,30 @@ void Node::paintPolygon(const QList<QPointF> listPoint)
|
||||
|
||||
// strategy needs points in vPointF format
|
||||
QVector<QPointF> points = points.fromList(listPoint);
|
||||
- KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle, fillStyle);
|
||||
helper.paintPolygon(points);
|
||||
}
|
||||
|
||||
|
||||
-void Node::paintEllipse(const QRectF &rect)
|
||||
+void Node::paintEllipse(const QRectF &rect, const QString strokeStyle, const QString fillStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintEllipse() on an unpaintable node, ignoring.";
|
||||
return;
|
||||
}
|
||||
|
||||
- KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle, fillStyle);
|
||||
helper.paintEllipse(rect);
|
||||
}
|
||||
|
||||
|
||||
-void Node::paintPath(const QPainterPath &path)
|
||||
+void Node::paintPath(const QPainterPath &path, const QString strokeStyle, const QString fillStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintPath() on an unpaintable node, ignoring.";
|
||||
return;
|
||||
}
|
||||
|
||||
- KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle, fillStyle);
|
||||
helper.paintPainterPath(path);
|
||||
}
|
||||
diff --git a/libs/libkis/Node.h b/libs/libkis/Node.h
|
||||
index 89a6f40..ecf9845 100644
|
||||
--- a/libs/libkis/Node.h
|
||||
+++ b/libs/libkis/Node.h
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "kritalibkis_export.h"
|
||||
#include "libkis.h"
|
||||
|
||||
+#include "PaintingResources.h"
|
||||
+
|
||||
/**
|
||||
* Node represents a layer or mask in a Krita image's Node hierarchy. Group layers can contain
|
||||
* other layers and masks; layers can contain masks.
|
||||
@@ -574,33 +576,101 @@ public Q_SLOTS:
|
||||
* @brief paint a line on the canvas. Uses current brush preset
|
||||
* @param pointOne starting point
|
||||
* @param pointTwo end point
|
||||
+ * @param strokeStyle appearance of the outline, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None - will use Foreground Color, since line would be invisible otherwise
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * </ul>
|
||||
*/
|
||||
- void paintLine(const QPointF pointOne, const QPointF pointTwo);
|
||||
+ void paintLine(const QPointF pointOne, const QPointF pointTwo, const QString strokeStyle = PaintingResources::defaultStrokeStyle);
|
||||
|
||||
/**
|
||||
* @brief paint a rectangle on the canvas. Uses current brush preset
|
||||
* @param rect QRect with x, y, width, and height
|
||||
+ * @param strokeStyle appearance of the outline, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * </ul>
|
||||
+ * Default is ForegroundColor.
|
||||
+ * @param fillStyle appearance of the fill, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * <li>Pattern</li>
|
||||
+ * </ul>
|
||||
+ * Default is None.
|
||||
*/
|
||||
- void paintRectangle(const QRectF &rect);
|
||||
+ void paintRectangle(const QRectF &rect,
|
||||
+ const QString strokeStyle = PaintingResources::defaultStrokeStyle,
|
||||
+ const QString fillStyle = PaintingResources::defaultFillStyle);
|
||||
|
||||
/**
|
||||
* @brief paint a polygon on the canvas. Uses current brush preset
|
||||
* @param list of Qpoints
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * </ul>
|
||||
+ * Default is ForegroundColor.
|
||||
+ * @param fillStyle appearance of the fill, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * <li>Pattern</li>
|
||||
+ * </ul>
|
||||
+ * Default is None.
|
||||
*/
|
||||
- void paintPolygon(const QList<QPointF> points);
|
||||
-
|
||||
+ void paintPolygon(const QList<QPointF> points,
|
||||
+ const QString strokeStyle = PaintingResources::defaultStrokeStyle,
|
||||
+ const QString fillStyle = PaintingResources::defaultFillStyle);
|
||||
/**
|
||||
* @brief paint an ellipse on the canvas. Uses current brush preset
|
||||
* @param rect QRect with x, y, width, and height
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * </ul>
|
||||
+ * Default is ForegroundColor.
|
||||
+ * @param fillStyle appearance of the fill, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * <li>Pattern</li>
|
||||
+ * </ul>
|
||||
+ * Default is None.
|
||||
*/
|
||||
- void paintEllipse(const QRectF &rect);
|
||||
-
|
||||
+ void paintEllipse(const QRectF &rect,
|
||||
+ const QString strokeStyle = PaintingResources::defaultStrokeStyle,
|
||||
+ const QString fillStyle = PaintingResources::defaultFillStyle);
|
||||
/**
|
||||
* @brief paint a custom path on the canvas. Uses current brush preset
|
||||
* @param path QPainterPath to determine path
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * </ul>
|
||||
+ * Default is ForegroundColor.
|
||||
+ * @param fillStyle appearance of the fill, one of:
|
||||
+ * <ul>
|
||||
+ * <li>None
|
||||
+ * <li>ForegroundColor</li>
|
||||
+ * <li>BackgroundColor</li>
|
||||
+ * <li>Pattern</li>
|
||||
+ * </ul>
|
||||
+ * Default is None.
|
||||
*/
|
||||
- void paintPath(const QPainterPath &path);
|
||||
-
|
||||
+ void paintPath(const QPainterPath &path,
|
||||
+ const QString strokeStyle = PaintingResources::defaultStrokeStyle,
|
||||
+ const QString fillStyle = PaintingResources::defaultFillStyle);
|
||||
/**
|
||||
* @brief paintAbility can be used to determine whether this node can be painted on with the current brush preset.
|
||||
* @return QString, one of the following:
|
||||
@@ -610,6 +680,7 @@ public Q_SLOTS:
|
||||
* <li>PAINT - This node is paintable by the current brush preset.</li>
|
||||
* <li>UNPAINTABLE - This node is not paintable, or a null preset is somehow selected./li>
|
||||
* <li>MYPAINTBRUSH_UNPAINTABLE - This node's non-RGBA colorspace cannot be painted on by the currently selected MyPaint brush.</li>
|
||||
+ * </ul>
|
||||
*/
|
||||
QString paintAbility();
|
||||
|
||||
diff --git a/libs/libkis/PaintingResources.cpp b/libs/libkis/PaintingResources.cpp
|
||||
index 62abb26..58d67ae 100644
|
||||
--- a/libs/libkis/PaintingResources.cpp
|
||||
+++ b/libs/libkis/PaintingResources.cpp
|
||||
@@ -53,9 +53,28 @@
|
||||
#include "kis_painting_information_builder.h"
|
||||
#include "KisAsynchronousStrokeUpdateHelper.h"
|
||||
#include "kis_stroke_strategy.h"
|
||||
-
|
||||
-
|
||||
-KisFigurePaintingToolHelper PaintingResources::createHelper(KisImageWSP image)
|
||||
+#include "KisViewManager.h"
|
||||
+#include "KisMainWindow.h"
|
||||
+#include "kis_image.h"
|
||||
+#include "KisToolShapeUtils.h"
|
||||
+
|
||||
+
|
||||
+const QStringList StrokeStyle = {
|
||||
+ "None", // 0 = KisToolShapeUtils::StrokeStyle::StrokeStyleNone
|
||||
+ "ForegroundColor", // KisToolShapeUtils::StrokeStyle::StrokeStyleForeground
|
||||
+ "BackgroundColor" // KisToolShapeUtils::StrokeStyle::StrokeStyleBackground
|
||||
+};
|
||||
+
|
||||
+const QStringList FillStyle = {
|
||||
+ "None", // 0 = KisToolShapeUtils::FillStyle::FillStyleNone
|
||||
+ "ForegroundColor", // KisToolShapeUtils::FillStyle::FillStyleForegroundColor
|
||||
+ "BackgroundColor", // KisToolShapeUtils::FillStyle::FillStyleBackgroundColor
|
||||
+ "Pattern" // KisToolShapeUtils::FillStyle::FillStylePattern
|
||||
+};
|
||||
+
|
||||
+KisFigurePaintingToolHelper PaintingResources::createHelper(KisImageWSP image,
|
||||
+ const QString strokeStyleString,
|
||||
+ const QString fillStyleString)
|
||||
{
|
||||
// need to grab the resource provider
|
||||
KisView *activeView = KisPart::instance()->currentMainwindow()->activeView();
|
||||
@@ -64,13 +83,35 @@ KisFigurePaintingToolHelper PaintingResources::createHelper(KisImageWSP image)
|
||||
// grab the image and current layer
|
||||
KisNodeSP node = activeView->currentNode();
|
||||
|
||||
- const KUndo2MagicString name = kundo2_noi18n("python_stroke");
|
||||
+ int strokeIndex = StrokeStyle.indexOf(strokeStyleString);
|
||||
+ if (strokeIndex == -1) {
|
||||
+ dbgScript << "Script tried to paint with invalid strokeStyle" << strokeStyleString << ", ignoring and using" << defaultStrokeStyle << ".";
|
||||
+ strokeIndex = StrokeStyle.indexOf(defaultStrokeStyle);
|
||||
+ if (strokeIndex == -1) {
|
||||
+ warnScript << "PaintingResources::createHelper(): defaultStrokeStyle" << defaultStrokeStyle << "is invalid!";
|
||||
+ strokeIndex = 1;
|
||||
+ }
|
||||
+ }
|
||||
+ KisToolShapeUtils::StrokeStyle strokeStyle = (KisToolShapeUtils::StrokeStyle) strokeIndex;
|
||||
+
|
||||
+ int fillIndex = FillStyle.indexOf(fillStyleString);
|
||||
+ if (fillIndex == -1) {
|
||||
+ dbgScript << "Script tried to paint with invalid fillStyle" << fillStyleString << ", ignoring and using" << defaultFillStyle << ".";
|
||||
+ fillIndex = FillStyle.indexOf(defaultFillStyle);
|
||||
+ if (fillIndex == -1) {
|
||||
+ warnScript << "PaintingResources::createHelper(): defaultFillStyle" << defaultFillStyle << " is invalid!";
|
||||
+ fillIndex = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ KisToolShapeUtils::FillStyle fillStyle = (KisToolShapeUtils::FillStyle) fillIndex;
|
||||
+
|
||||
+ const KUndo2MagicString name = kundo2_i18n("Scripted Brush Stroke");
|
||||
KisFigurePaintingToolHelper helper(
|
||||
name,
|
||||
image,
|
||||
node, resourceManager,
|
||||
- KisToolShapeUtils::StrokeStyle::StrokeStyleForeground,
|
||||
- KisToolShapeUtils::FillStyle::FillStyleNone
|
||||
+ strokeStyle,
|
||||
+ fillStyle
|
||||
);
|
||||
|
||||
return helper;
|
||||
diff --git a/libs/libkis/PaintingResources.h b/libs/libkis/PaintingResources.h
|
||||
index 19bb0d4..174057a 100644
|
||||
--- a/libs/libkis/PaintingResources.h
|
||||
+++ b/libs/libkis/PaintingResources.h
|
||||
@@ -35,12 +35,19 @@
|
||||
/**
|
||||
* @brief The PaintingResources namespace
|
||||
* Sets up information related to making painting strokes.
|
||||
- * Used primarily in the Document class
|
||||
+ * Used primarily in the Node class
|
||||
*
|
||||
*/
|
||||
namespace PaintingResources
|
||||
{
|
||||
- KisFigurePaintingToolHelper createHelper(KisImageWSP image);
|
||||
+ // These are set in Node.sip
|
||||
+ const QString defaultStrokeStyle = "ForegroundColor";
|
||||
+ const QString defaultFillStyle = "None";
|
||||
+
|
||||
+ KisFigurePaintingToolHelper createHelper(KisImageWSP image,
|
||||
+ const QString strokeStyle = defaultStrokeStyle,
|
||||
+ const QString fillStyle = defaultFillStyle);
|
||||
+
|
||||
};
|
||||
|
||||
#endif // LIBKIS_PAINTINGRESOURCES_H
|
||||
diff --git a/plugins/extensions/pykrita/sip/krita/Node.sip b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
index 6270bd9..884e615 100644
|
||||
--- a/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
+++ b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
@@ -70,11 +70,11 @@ public Q_SLOTS:
|
||||
int index() const;
|
||||
QUuid uniqueId() const;
|
||||
|
||||
- void paintLine(const QPoint pointOne, const QPoint pointTwo);
|
||||
- void paintRectangle(const QRectF &rect);
|
||||
- void paintPolygon(const QList<QPointF> points);
|
||||
- void paintEllipse(const QRectF &rect);
|
||||
- void paintPath(const QPainterPath &path);
|
||||
+ void paintLine(const QPoint pointOne, const QPoint pointTwo, const QString strokeStyle = "ForegroundColor");
|
||||
+ void paintRectangle(const QRectF &rect, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
+ void paintPolygon(const QList<QPointF> points, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
+ void paintEllipse(const QRectF &rect, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
+ void paintPath(const QPainterPath &path, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
QString paintAbility();
|
||||
Q_SIGNALS:
|
||||
private:
|
66
pkgs/krita/painting-api-pressure.patch
Normal file
66
pkgs/krita/painting-api-pressure.patch
Normal file
|
@ -0,0 +1,66 @@
|
|||
diff --git a/libs/libkis/Node.cpp b/libs/libkis/Node.cpp
|
||||
index 7e15b58c2c..a187c18aad 100644
|
||||
--- a/libs/libkis/Node.cpp
|
||||
+++ b/libs/libkis/Node.cpp
|
||||
@@ -863,7 +863,7 @@ QString Node::paintAbility()
|
||||
return "UNPAINTABLE";
|
||||
}
|
||||
|
||||
-void Node::paintLine(const QPointF pointOne, const QPointF pointTwo, const QString strokeStyle)
|
||||
+void Node::paintLine(const QPointF pointOne, const QPointF pointTwo, double pressureOne, double pressureTwo, const QString strokeStyle)
|
||||
{
|
||||
if (paintAbility() != "PAINT") {
|
||||
dbgScript << "Script attempted to use Node::paintLine() on an unpaintable node, ignoring.";
|
||||
@@ -871,11 +871,11 @@ void Node::paintLine(const QPointF pointOne, const QPointF pointTwo, const QStri
|
||||
}
|
||||
|
||||
KisPaintInformation pointOneInfo;
|
||||
- pointOneInfo.setPressure(1.0);
|
||||
+ pointOneInfo.setPressure(pressureOne);
|
||||
pointOneInfo.setPos(pointOne);
|
||||
|
||||
KisPaintInformation pointTwoInfo;
|
||||
- pointTwoInfo.setPressure(1.0);
|
||||
+ pointTwoInfo.setPressure(pressureTwo);
|
||||
pointTwoInfo.setPos(pointTwo);
|
||||
|
||||
KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image, strokeStyle);
|
||||
diff --git a/libs/libkis/Node.h b/libs/libkis/Node.h
|
||||
index ecf9845a22..ce63d3f1bc 100644
|
||||
--- a/libs/libkis/Node.h
|
||||
+++ b/libs/libkis/Node.h
|
||||
@@ -576,6 +576,8 @@ public Q_SLOTS:
|
||||
* @brief paint a line on the canvas. Uses current brush preset
|
||||
* @param pointOne starting point
|
||||
* @param pointTwo end point
|
||||
+ * @param pressureOne starting pressure
|
||||
+ * @param pressureTwo end pressure
|
||||
* @param strokeStyle appearance of the outline, one of:
|
||||
* <ul>
|
||||
* <li>None - will use Foreground Color, since line would be invisible otherwise
|
||||
@@ -583,7 +585,11 @@ public Q_SLOTS:
|
||||
* <li>BackgroundColor</li>
|
||||
* </ul>
|
||||
*/
|
||||
- void paintLine(const QPointF pointOne, const QPointF pointTwo, const QString strokeStyle = PaintingResources::defaultStrokeStyle);
|
||||
+ void paintLine(const QPointF pointOne,
|
||||
+ const QPointF pointTwo,
|
||||
+ double pressureOne = 1.0,
|
||||
+ double pressureTwo = 1.0,
|
||||
+ const QString strokeStyle = PaintingResources::defaultStrokeStyle);
|
||||
|
||||
/**
|
||||
* @brief paint a rectangle on the canvas. Uses current brush preset
|
||||
diff --git a/plugins/extensions/pykrita/sip/krita/Node.sip b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
index a01a6bce6f..986cc54169 100644
|
||||
--- a/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
+++ b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
@@ -82,7 +82,7 @@ public Q_SLOTS:
|
||||
int index() const;
|
||||
QUuid uniqueId() const;
|
||||
|
||||
- void paintLine(const QPoint pointOne, const QPoint pointTwo, const QString strokeStyle = "ForegroundColor");
|
||||
+ void paintLine(const QPoint pointOne, const QPoint pointTwo, double pressureOne = 1.0, double pressureTwo = 1.0, const QString strokeStyle = "ForegroundColor");
|
||||
void paintRectangle(const QRectF &rect, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
void paintPolygon(const QList<QPointF> points, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
||||
void paintEllipse(const QRectF &rect, const QString strokeStyle = "ForegroundColor", const QString fillStyle = "None");
|
309
pkgs/krita/painting-api.patch
Normal file
309
pkgs/krita/painting-api.patch
Normal file
|
@ -0,0 +1,309 @@
|
|||
diff --git a/libs/libkis/CMakeLists.txt b/libs/libkis/CMakeLists.txt
|
||||
index a337451..66a5166 100644
|
||||
--- a/libs/libkis/CMakeLists.txt
|
||||
+++ b/libs/libkis/CMakeLists.txt
|
||||
@@ -10,6 +10,7 @@ set(kritalibkis_LIB_SRCS
|
||||
ManagedColor.cpp
|
||||
Node.cpp
|
||||
Notifier.cpp
|
||||
+ PaintingResources.cpp
|
||||
PresetChooser.cpp
|
||||
Preset.cpp
|
||||
Palette.cpp
|
||||
diff --git a/libs/libkis/Document.h b/libs/libkis/Document.h
|
||||
index 998a350..841c319 100644
|
||||
--- a/libs/libkis/Document.h
|
||||
+++ b/libs/libkis/Document.h
|
||||
@@ -6,8 +6,6 @@
|
||||
#ifndef LIBKIS_DOCUMENT_H
|
||||
#define LIBKIS_DOCUMENT_H
|
||||
|
||||
-#include <QObject>
|
||||
-
|
||||
#include "kritalibkis_export.h"
|
||||
#include "libkis.h"
|
||||
|
||||
diff --git a/libs/libkis/Node.cpp b/libs/libkis/Node.cpp
|
||||
index 3fd7b5a..84f24d3 100644
|
||||
--- a/libs/libkis/Node.cpp
|
||||
+++ b/libs/libkis/Node.cpp
|
||||
@@ -67,6 +67,17 @@
|
||||
#include "LibKisUtils.h"
|
||||
#include <kis_layer_utils.h>
|
||||
|
||||
+#include <KoCanvasResourceProvider.h>
|
||||
+#include "strokes/KisFreehandStrokeInfo.h"
|
||||
+#include "kis_resources_snapshot.h"
|
||||
+#include "kis_canvas_resource_provider.h"
|
||||
+#include "strokes/freehand_stroke.h"
|
||||
+#include "kis_painting_information_builder.h"
|
||||
+#include "KisAsynchronousStrokeUpdateHelper.h"
|
||||
+#include "kis_stroke_strategy.h"
|
||||
+#include "PaintingResources.h"
|
||||
+
|
||||
+
|
||||
struct Node::Private {
|
||||
Private() {}
|
||||
KisImageWSP image;
|
||||
@@ -821,3 +832,50 @@ KisNodeSP Node::node() const
|
||||
{
|
||||
return d->node;
|
||||
}
|
||||
+
|
||||
+void Node::paintLine(const QPointF pointOne, const QPointF pointTwo)
|
||||
+{
|
||||
+ KisPaintInformation pointOneInfo;
|
||||
+ pointOneInfo.setPressure(1.0);
|
||||
+ pointOneInfo.setPos(pointOne);
|
||||
+
|
||||
+ KisPaintInformation pointTwoInfo;
|
||||
+ pointTwoInfo.setPressure(1.0);
|
||||
+ pointTwoInfo.setPos(pointTwo);
|
||||
+
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ helper.paintLine(pointOneInfo, pointTwoInfo);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void Node::paintRectangle(const QRectF &rect)
|
||||
+{
|
||||
+ // reference class where this stuff is being done. Maybe can use the "facade" like that does for setup?
|
||||
+ // void KisFigurePaintingToolHelper::paintRect(const QRectF &rect)
|
||||
+
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ helper.paintRect(rect);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void Node::paintPolygon(const QList<QPointF> listPoint)
|
||||
+{
|
||||
+ // strategy needs points in vPointF format
|
||||
+ QVector<QPointF> points = points.fromList(listPoint);
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ helper.paintPolygon(points);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void Node::paintEllipse(const QRectF &rect)
|
||||
+{
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ helper.paintEllipse(rect);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+void Node::paintPath(const QPainterPath &path)
|
||||
+{
|
||||
+ KisFigurePaintingToolHelper helper = PaintingResources::createHelper(d->image);
|
||||
+ helper.paintPainterPath(path);
|
||||
+}
|
||||
diff --git a/libs/libkis/Node.h b/libs/libkis/Node.h
|
||||
index 1a40372..10daba4 100644
|
||||
--- a/libs/libkis/Node.h
|
||||
+++ b/libs/libkis/Node.h
|
||||
@@ -570,6 +570,36 @@ public Q_SLOTS:
|
||||
*/
|
||||
QUuid uniqueId() const;
|
||||
|
||||
+ /**
|
||||
+ * @brief paint a line on the canvas. Uses current brush preset
|
||||
+ * @param pointOne starting point
|
||||
+ * @param pointTwo end point
|
||||
+ */
|
||||
+ void paintLine(const QPointF pointOne, const QPointF pointTwo);
|
||||
+
|
||||
+ /**
|
||||
+ * @brief paint a rectangle on the canvas. Uses current brush preset
|
||||
+ * @param rect QRect with x, y, width, and height
|
||||
+ */
|
||||
+ void paintRectangle(const QRectF &rect);
|
||||
+
|
||||
+ /**
|
||||
+ * @brief paint a polygon on the canvas. Uses current brush preset
|
||||
+ * @param list of Qpoints
|
||||
+ */
|
||||
+ void paintPolygon(const QList<QPointF> points);
|
||||
+
|
||||
+ /**
|
||||
+ * @brief paint an ellipse on the canvas. Uses current brush preset
|
||||
+ * @param rect QRect with x, y, width, and height
|
||||
+ */
|
||||
+ void paintEllipse(const QRectF &rect);
|
||||
+
|
||||
+ /**
|
||||
+ * @brief paint a custom path on the canvas. Uses current brush preset
|
||||
+ * @param path QPainterPath to determine path
|
||||
+ */
|
||||
+ void paintPath(const QPainterPath &path);
|
||||
|
||||
private:
|
||||
|
||||
diff --git a/libs/libkis/PaintingResources.cpp b/libs/libkis/PaintingResources.cpp
|
||||
new file mode 100644
|
||||
index 0000000..62abb26
|
||||
--- /dev/null
|
||||
+++ b/libs/libkis/PaintingResources.cpp
|
||||
@@ -0,0 +1,77 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2020 Scott Petrovic <scottpetrovic@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU Lesser General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 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 Lesser General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+#include "PaintingResources.h"
|
||||
+
|
||||
+#include <kis_types.h>
|
||||
+
|
||||
+#include "KisView.h"
|
||||
+#include "kis_types.h"
|
||||
+
|
||||
+#include "kis_canvas_resource_provider.h"
|
||||
+#include "kis_paintop_preset.h"
|
||||
+
|
||||
+#include "KisViewManager.h"
|
||||
+#include "KisGlobalResourcesInterface.h"
|
||||
+
|
||||
+#include <KoResourcePaths.h>
|
||||
+
|
||||
+#include "Document.h"
|
||||
+
|
||||
+#include <KisPart.h>
|
||||
+#include <KisMainWindow.h>
|
||||
+
|
||||
+#include <kis_types.h>
|
||||
+#include <kis_annotation.h>
|
||||
+
|
||||
+
|
||||
+
|
||||
+#include "kis_animation_importer.h"
|
||||
+#include <kis_canvas2.h>
|
||||
+#include <KoUpdater.h>
|
||||
+#include <QMessageBox>
|
||||
+
|
||||
+
|
||||
+#include "strokes/KisFreehandStrokeInfo.h"
|
||||
+#include "kis_resources_snapshot.h"
|
||||
+#include "kis_canvas_resource_provider.h"
|
||||
+#include "strokes/freehand_stroke.h"
|
||||
+#include "kis_painting_information_builder.h"
|
||||
+#include "KisAsynchronousStrokeUpdateHelper.h"
|
||||
+#include "kis_stroke_strategy.h"
|
||||
+
|
||||
+
|
||||
+KisFigurePaintingToolHelper PaintingResources::createHelper(KisImageWSP image)
|
||||
+{
|
||||
+ // need to grab the resource provider
|
||||
+ KisView *activeView = KisPart::instance()->currentMainwindow()->activeView();
|
||||
+ KoCanvasResourceProvider *resourceManager = activeView->viewManager()->canvasResourceProvider()->resourceManager();
|
||||
+
|
||||
+ // grab the image and current layer
|
||||
+ KisNodeSP node = activeView->currentNode();
|
||||
+
|
||||
+ const KUndo2MagicString name = kundo2_noi18n("python_stroke");
|
||||
+ KisFigurePaintingToolHelper helper(
|
||||
+ name,
|
||||
+ image,
|
||||
+ node, resourceManager,
|
||||
+ KisToolShapeUtils::StrokeStyle::StrokeStyleForeground,
|
||||
+ KisToolShapeUtils::FillStyle::FillStyleNone
|
||||
+ );
|
||||
+
|
||||
+ return helper;
|
||||
+}
|
||||
diff --git a/libs/libkis/PaintingResources.h b/libs/libkis/PaintingResources.h
|
||||
new file mode 100644
|
||||
index 0000000..19bb0d4
|
||||
--- /dev/null
|
||||
+++ b/libs/libkis/PaintingResources.h
|
||||
@@ -0,0 +1,46 @@
|
||||
+/*
|
||||
+ * Copyright (c) 2020 Scott Petrovic <scottpetrovic@gmail.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU Lesser General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 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 Lesser General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+#ifndef LIBKIS_PAINTINGRESOURCES_H
|
||||
+#define LIBKIS_PAINTINGRESOURCES_H
|
||||
+
|
||||
+#include <QObject>
|
||||
+#include <QColor>
|
||||
+#include <kis_types.h>
|
||||
+
|
||||
+#include "kritalibkis_export.h"
|
||||
+#include "KoCanvasResourceProvider.h"
|
||||
+#include "kis_stroke_strategy.h"
|
||||
+
|
||||
+#include <kis_figure_painting_tool_helper.h>
|
||||
+
|
||||
+#include "libkis.h"
|
||||
+
|
||||
+#include "View.h"
|
||||
+
|
||||
+/**
|
||||
+ * @brief The PaintingResources namespace
|
||||
+ * Sets up information related to making painting strokes.
|
||||
+ * Used primarily in the Document class
|
||||
+ *
|
||||
+ */
|
||||
+namespace PaintingResources
|
||||
+{
|
||||
+ KisFigurePaintingToolHelper createHelper(KisImageWSP image);
|
||||
+};
|
||||
+
|
||||
+#endif // LIBKIS_PAINTINGRESOURCES_H
|
||||
diff --git a/libs/ui/tool/kis_resources_snapshot.cpp b/libs/ui/tool/kis_resources_snapshot.cpp
|
||||
index dca6ba5..0c031e0 100644
|
||||
--- a/libs/ui/tool/kis_resources_snapshot.cpp
|
||||
+++ b/libs/ui/tool/kis_resources_snapshot.cpp
|
||||
@@ -75,8 +75,11 @@ KisResourcesSnapshot::KisResourcesSnapshot(KisImageSP image, KisNodeSP currentNo
|
||||
m_d->currentBgColor = resourceManager->resource(KoCanvasResource::BackgroundColor).value<KoColor>();
|
||||
m_d->currentPattern = resourceManager->resource(KoCanvasResource::CurrentPattern).value<KoPatternSP>();
|
||||
if (resourceManager->resource(KoCanvasResource::CurrentGradient).value<KoAbstractGradientSP>()) {
|
||||
- m_d->currentGradient = resourceManager->resource(KoCanvasResource::CurrentGradient).value<KoAbstractGradientSP>()
|
||||
- ->cloneAndBakeVariableColors(m_d->globalCanvasResourcesInterface);
|
||||
+ m_d->currentGradient = resourceManager->resource(KoCanvasResource::CurrentGradient).value<KoAbstractGradientSP>();
|
||||
+ if(m_d->currentGradient) {
|
||||
+ m_d->currentGradient = resourceManager->resource(KoCanvasResource::CurrentGradient).value<KoAbstractGradientSP>()
|
||||
+ ->cloneAndBakeVariableColors(m_d->globalCanvasResourcesInterface);
|
||||
+ }
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/plugins/extensions/pykrita/sip/krita/Node.sip b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
index 3066bfb..cbcef0f 100644
|
||||
--- a/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
+++ b/plugins/extensions/pykrita/sip/krita/Node.sip
|
||||
@@ -69,6 +69,12 @@ public Q_SLOTS:
|
||||
void setLayerStyleFromAsl(const QString &asl);
|
||||
int index() const;
|
||||
QUuid uniqueId() const;
|
||||
+
|
||||
+ void paintLine(const QPoint pointOne, const QPoint pointTwo);
|
||||
+ void paintRectangle(const QRectF &rect);
|
||||
+ void paintPolygon(const QList<QPointF> points);
|
||||
+ void paintEllipse(const QRectF &rect);
|
||||
+ void paintPath(const QPainterPath &path);
|
||||
Q_SIGNALS:
|
||||
private:
|
||||
};
|
26
pkgs/sway/0001-mobile-reverse-layer-order.patch
Normal file
26
pkgs/sway/0001-mobile-reverse-layer-order.patch
Normal file
|
@ -0,0 +1,26 @@
|
|||
From 7fead3cd2158fe913775ede5651291cf5f4ccf4d Mon Sep 17 00:00:00 2001
|
||||
From: chayleaf <chayleaf-git@pavluk.org>
|
||||
Date: Wed, 14 Aug 2024 07:32:11 +0700
|
||||
Subject: [PATCH 1/2] mobile: reverse layer order
|
||||
|
||||
This makes exclusive anchored layers that were added first be first
|
||||
---
|
||||
sway/desktop/layer_shell.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
|
||||
index 8c6cedfe..41a638ee 100644
|
||||
--- a/sway/desktop/layer_shell.c
|
||||
+++ b/sway/desktop/layer_shell.c
|
||||
@@ -129,7 +129,7 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list,
|
||||
struct wlr_box full_area = { 0 };
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&full_area.width, &full_area.height);
|
||||
- wl_list_for_each(sway_layer, list, link) {
|
||||
+ wl_list_for_each_reverse(sway_layer, list, link) {
|
||||
struct wlr_layer_surface_v1 *layer = sway_layer->layer_surface;
|
||||
struct wlr_layer_surface_v1_state *state = &layer->current;
|
||||
if (exclusive != (state->exclusive_zone > 0)) {
|
||||
--
|
||||
2.44.1
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
From 466d750b96184b793d276d9d0e30d37af4477fea Mon Sep 17 00:00:00 2001
|
||||
From: chayleaf <chayleaf-git@pavluk.org>
|
||||
Date: Wed, 14 Aug 2024 08:17:44 +0700
|
||||
Subject: [PATCH 2/2] mobile: don't idle_notify for volume keys
|
||||
|
||||
---
|
||||
sway/input/keyboard.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
|
||||
index 8927287f..d42f62b0 100644
|
||||
--- a/sway/input/keyboard.c
|
||||
+++ b/sway/input/keyboard.c
|
||||
@@ -404,7 +404,9 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||
keyboard->seat_device->input_device->wlr_device;
|
||||
char *device_identifier = input_device_get_identifier(wlr_device);
|
||||
bool exact_identifier = keyboard->wlr->group != NULL;
|
||||
- seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
||||
+ if (event->keycode != XKB_KEY_XF86AudioLowerVolume && event->keycode != XKB_KEY_XF86AudioRaiseVolume) {
|
||||
+ seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
|
||||
+ }
|
||||
bool input_inhibited = seat->exclusive_client != NULL ||
|
||||
server.session_lock.locked;
|
||||
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
|
||||
--
|
||||
2.44.1
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
{ config
|
||||
, lib
|
||||
, pkgs
|
||||
, router-config
|
||||
, hardware
|
||||
|
@ -126,14 +127,16 @@ in
|
|||
options = [ "defaults" "size=2G" "mode=755" ]; };
|
||||
"/persist" =
|
||||
{ device = "UUID=${uuids.bch}"; fsType = "bcachefs"; inherit neededForBoot;
|
||||
# TODO: https://github.com/systemd/systemd/pull/33720/files
|
||||
options = [
|
||||
# TODO: remove the if when systemd >= 257
|
||||
options = let
|
||||
dep = if lib.versionAtLeast config.boot.initrd.systemd.package.version "257" then "wants" else "requires";
|
||||
in [
|
||||
"degraded"
|
||||
"errors=ro"
|
||||
"x-systemd.device-timeout=0"
|
||||
"x-systemd.requires=dev-mapper-bch0.device"
|
||||
"x-systemd.requires=dev-mapper-bch1.device"
|
||||
"x-systemd.requires=dev-mapper-bch2.device"
|
||||
"x-systemd.${dep}=dev-mapper-bch0.device"
|
||||
"x-systemd.${dep}=dev-mapper-bch1.device"
|
||||
"x-systemd.${dep}=dev-mapper-bch2.device"
|
||||
]; };
|
||||
"/boot" = { device = parts.boot; fsType = "vfat"; inherit neededForBoot; };
|
||||
};
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"steam-original"
|
||||
];
|
||||
hardware = {
|
||||
opentabletdriver.enable = true;
|
||||
steam-hardware.enable = true;
|
||||
opengl.driSupport32Bit = true;
|
||||
# needed for sway WLR_RENDERER=vulkan
|
||||
|
|
20
system/hosts/router/a.py
Normal file
20
system/hosts/router/a.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
import traceback
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import pytricia # type: ignore
|
||||
|
||||
def build_ipset(ips: list[str]) -> pytricia.PyTricia:
|
||||
pyt = pytricia.PyTricia()
|
||||
for ip in ips:
|
||||
try:
|
||||
pyt.insert(ip, None)
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
f.write(f"Warning: couldn't insert ip {ip}:\n")
|
||||
traceback.print_exc(file=f)
|
||||
return pyt
|
||||
|
||||
s = build_ipset(["10.0.0.0/24"])
|
|
@ -178,12 +178,8 @@
|
|||
#
|
||||
|
||||
import gi
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import pydbus
|
||||
import pytricia # type: ignore
|
||||
import re
|
||||
import array
|
||||
import threading
|
||||
|
@ -205,22 +201,6 @@ from typing import TypedDict, Optional, Any
|
|||
IF_UNSPEC = -1
|
||||
PROTO_UNSPEC = -1
|
||||
|
||||
|
||||
Domains = dict[str, "Domains | bool"]
|
||||
|
||||
|
||||
class NftQuery(TypedDict):
|
||||
domains: Domains
|
||||
ips4: pytricia.PyTricia
|
||||
ips6: pytricia.PyTricia
|
||||
name4: str
|
||||
name6: str
|
||||
dynamic: bool
|
||||
|
||||
|
||||
NFT_QUERIES: dict[str, NftQuery] = {}
|
||||
# dynamic query update token
|
||||
NFT_TOKEN: str = ""
|
||||
DOMAIN_NAME_OVERRIDES: dict[str, str] = {}
|
||||
DEBUG = False
|
||||
MDNS_TTL: int
|
||||
|
@ -239,22 +219,6 @@ dbus_thread: threading.Thread
|
|||
dbus_loop: Any
|
||||
|
||||
|
||||
def is_valid_ip4(x: str) -> bool:
|
||||
try:
|
||||
_ = ipaddress.IPv4Address(x)
|
||||
return True
|
||||
except ipaddress.AddressValueError:
|
||||
return False
|
||||
|
||||
|
||||
def is_valid_ip6(x: str) -> bool:
|
||||
try:
|
||||
_ = ipaddress.IPv6Address(x)
|
||||
return True
|
||||
except ipaddress.AddressValueError:
|
||||
return False
|
||||
|
||||
|
||||
def str2bool(v: str) -> bool:
|
||||
if v.lower() in ["false", "no", "0", "off", ""]:
|
||||
return False
|
||||
|
@ -500,150 +464,11 @@ def parse_type_list(lst: str) -> list[RdataType]:
|
|||
)
|
||||
|
||||
|
||||
def build_ipset(ips: list[str]) -> pytricia.PyTricia:
|
||||
pyt = pytricia.PyTricia()
|
||||
for ip in ips:
|
||||
try:
|
||||
pyt.insert(ip, None)
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
f.write(f"Warning: couldn't insert ip {ip}:\n")
|
||||
traceback.print_exc(file=f)
|
||||
return pyt
|
||||
|
||||
|
||||
def add_ips(set: str, ipv6: bool, ips: list[str], flush: bool = False):
|
||||
# with open('/var/lib/unbound/info.log', 'at') as f:
|
||||
# print('set', set, 'ipv6', ipv6, 'ips', ips, file=f)
|
||||
pyt = build_ipset(ips)
|
||||
ruleset: list[dict] = []
|
||||
if flush:
|
||||
ruleset.append(
|
||||
{"flush": {"set": {"family": "inet", "table": "global", "name": set}}}
|
||||
)
|
||||
elems: list[str | dict] = []
|
||||
if ipv6:
|
||||
maxn = 128
|
||||
is_valid: Callable[[str], bool] = is_valid_ip6
|
||||
else:
|
||||
maxn = 32
|
||||
is_valid = is_valid_ip4
|
||||
for ip in pyt.keys():
|
||||
try:
|
||||
if pyt.parent(ip) != None:
|
||||
continue
|
||||
except:
|
||||
pass
|
||||
if "/" not in ip:
|
||||
n: int = maxn
|
||||
else:
|
||||
ip, n0 = ip.split("/")
|
||||
try:
|
||||
n = int(n0)
|
||||
except:
|
||||
continue
|
||||
if not is_valid(ip):
|
||||
continue
|
||||
if n == maxn:
|
||||
elems.append(ip)
|
||||
else:
|
||||
elems.append({"prefix": {"addr": ip, "len": n}})
|
||||
# with open('/var/lib/unbound/info.log', 'at') as f:
|
||||
# print('elems', elems, file=f)
|
||||
if len(elems) == 0:
|
||||
return
|
||||
ruleset.append(
|
||||
{
|
||||
"add": {
|
||||
"element": {
|
||||
"family": "inet",
|
||||
"table": "global",
|
||||
"name": set,
|
||||
"elem": elems,
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
data: bytes = json.dumps({"nftables": ruleset}).encode("utf-8")
|
||||
# with open('/var/lib/unbound/info.log', 'at') as f:
|
||||
# print('data', data, file=f)
|
||||
try:
|
||||
out = subprocess.run(
|
||||
["/run/current-system/sw/bin/nft", "-j", "-f", "/dev/stdin"],
|
||||
capture_output=True,
|
||||
input=data,
|
||||
)
|
||||
# with open('/var/lib/unbound/info.log', 'at') as f:
|
||||
# print('out', out, file=f)
|
||||
if out.returncode != 0:
|
||||
with open("/var/lib/unbound/nftables.log", "wb") as f:
|
||||
f.write(b"Error running nftables ruleset. Ruleset:\n")
|
||||
f.write(data)
|
||||
f.write(b"\n")
|
||||
f.write(b"stdout:\n")
|
||||
f.write(out.stdout)
|
||||
f.write(b"\nstderr:\n")
|
||||
f.write(out.stderr)
|
||||
f.write(b"\n")
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
f.write(f"While adding ips for set {set}:\n")
|
||||
traceback.print_exc(file=f)
|
||||
|
||||
|
||||
def add_split_domain(domains: Domains, split_domain: list[str]):
|
||||
if not split_domain:
|
||||
return
|
||||
split_domain = split_domain[:]
|
||||
if split_domain and split_domain[-1] == '*':
|
||||
split_domain.pop()
|
||||
if not split_domain:
|
||||
return
|
||||
while len(split_domain) > 1:
|
||||
key = split_domain[-1]
|
||||
if key in domains.keys():
|
||||
domains1 = domains[key]
|
||||
if isinstance(domains1, bool):
|
||||
return
|
||||
else:
|
||||
domains1 = {}
|
||||
domains[key] = domains1
|
||||
domains = domains1
|
||||
split_domain.pop()
|
||||
domains[split_domain[-1]] = True
|
||||
|
||||
|
||||
def build_domains(domains: list[str]) -> Domains:
|
||||
ret: Domains = {}
|
||||
for domain in domains:
|
||||
add_split_domain(ret, domain.split("."))
|
||||
return ret
|
||||
|
||||
|
||||
def lookup_domain(domains: Domains, domain: str) -> bool:
|
||||
split_domain: list[str] = domain.split(".")
|
||||
while len(split_domain):
|
||||
key: str = split_domain[-1]
|
||||
split_domain = split_domain[:-1]
|
||||
domains1 = domains.get(key, False)
|
||||
if isinstance(domains1, bool):
|
||||
return domains1
|
||||
domains = domains1
|
||||
return False
|
||||
|
||||
|
||||
class DpiInfo(TypedDict):
|
||||
domains: list[str]
|
||||
name: str
|
||||
restriction: dict
|
||||
|
||||
|
||||
def init(*args: Any, **kwargs: Any):
|
||||
global dbus_thread, DEBUG
|
||||
global MDNS_TTL, MDNS_GETONE, MDNS_TIMEOUT
|
||||
global MDNS_REJECT_TYPES, MDNS_ACCEPT_TYPES
|
||||
global MDNS_REJECT_NAMES, MDNS_ACCEPT_NAMES
|
||||
global NFT_QUERIES, NFT_TOKEN, DOMAIN_NAME_OVERRIDES
|
||||
|
||||
domain_name_overrides: str = os.environ.get("DOMAIN_NAME_OVERRIDES", "")
|
||||
if domain_name_overrides:
|
||||
|
@ -652,92 +477,6 @@ def init(*args: Any, **kwargs: Any):
|
|||
DOMAIN_NAME_OVERRIDES[k1] = v1
|
||||
DOMAIN_NAME_OVERRIDES[k1 + "."] = v1 + "."
|
||||
|
||||
NFT_TOKEN = os.environ.get("NFT_TOKEN", "")
|
||||
nft_queries: str = os.environ.get("NFT_QUERIES", "")
|
||||
if nft_queries:
|
||||
for query in nft_queries.split(";"):
|
||||
name, sets = query.split(":")
|
||||
dynamic = False
|
||||
if name.endswith("!"):
|
||||
name = name.rstrip("!")
|
||||
dynamic = True
|
||||
set4, set6 = sets.split(",")
|
||||
NFT_QUERIES[name] = {
|
||||
"domains": {},
|
||||
"ips4": [],
|
||||
"ips6": [],
|
||||
"name4": set4,
|
||||
"name6": set6,
|
||||
"dynamic": dynamic,
|
||||
}
|
||||
|
||||
for k, v in NFT_QUERIES.items():
|
||||
all_domains: list[str] = []
|
||||
for base in ["/etc/unbound", "/var/lib/unbound"]:
|
||||
try:
|
||||
with open(f"{base}/{k}_domains.json", "rt", encoding="utf-8") as f:
|
||||
domains: list[str] = json.load(f)
|
||||
all_domains.extend(domains)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
try:
|
||||
with open(f"{base}/{k}_dpi.json", "rt", encoding="utf-8") as f:
|
||||
dpi: list[DpiInfo] = json.load(f)
|
||||
for dpi_info in dpi:
|
||||
all_domains.extend(dpi_info["domains"])
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
try:
|
||||
with open(f"{base}/{k}_ips.json", "rt", encoding="utf-8") as f:
|
||||
ips: list[str] = json.load(f)
|
||||
v["ips4"].extend(filter(lambda x: "." in x, ips))
|
||||
v["ips6"].extend(filter(lambda x: ":" in x, ips))
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
v["domains"] = build_domains(all_domains)
|
||||
|
||||
# cached resolved domains
|
||||
try:
|
||||
os.makedirs("/var/lib/unbound/domains4/", exist_ok=True)
|
||||
for x in os.listdir("/var/lib/unbound/domains4/"):
|
||||
with open(f"/var/lib/unbound/domains4/{x}", "rt") as f:
|
||||
data = f.read().split("\n")
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if lookup_domain(v["domains"], x):
|
||||
v["ips4"].extend(data)
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
try:
|
||||
os.makedirs("/var/lib/unbound/domains6/", exist_ok=True)
|
||||
for x in os.listdir("/var/lib/unbound/domains6/"):
|
||||
with open(f"/var/lib/unbound/domains6/{x}", "rt") as f:
|
||||
data = f.read().split("\n")
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if lookup_domain(v["domains"], x):
|
||||
v["ips6"].extend(data)
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
|
||||
# finally, add the ips to nftables
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if v["ips4"] and v["name4"]:
|
||||
add_ips(v["name4"], False, v["ips4"], flush=True)
|
||||
if v["ips6"] and v["name6"]:
|
||||
add_ips(v["name6"], True, v["ips6"], flush=True)
|
||||
v["ips4"] = build_ipset(v["ips4"])
|
||||
v["ips6"] = build_ipset(v["ips6"])
|
||||
|
||||
DEBUG = str2bool(os.environ.get("DEBUG", str(False)))
|
||||
|
||||
MDNS_TTL = int(os.environ.get("MDNS_TTL", 120))
|
||||
|
@ -751,20 +490,20 @@ def init(*args: Any, **kwargs: Any):
|
|||
if MDNS_ACCEPT_TYPES:
|
||||
dbg(f"ONLY resolving the following types via Avahi: {MDNS_ACCEPT_TYPES}")
|
||||
|
||||
v2 = os.environ.get("MDNS_REJECT_NAMES", None)
|
||||
MDNS_REJECT_NAMES = re.compile(v2, flags=re.I | re.S) if v2 is not None else None
|
||||
v = os.environ.get("MDNS_REJECT_NAMES", None)
|
||||
MDNS_REJECT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
|
||||
if MDNS_REJECT_NAMES is not None:
|
||||
dbg(f"Names NOT resolved via Avahi: {MDNS_REJECT_NAMES.pattern}")
|
||||
|
||||
v2 = os.environ.get("MDNS_ACCEPT_NAMES", None)
|
||||
MDNS_ACCEPT_NAMES = re.compile(v2, flags=re.I | re.S) if v2 is not None else None
|
||||
v = os.environ.get("MDNS_ACCEPT_NAMES", None)
|
||||
MDNS_ACCEPT_NAMES = re.compile(v, flags=re.I | re.S) if v is not None else None
|
||||
if MDNS_ACCEPT_NAMES is not None:
|
||||
dbg(
|
||||
f"ONLY resolving the following names via Avahi: {MDNS_ACCEPT_NAMES.pattern}"
|
||||
)
|
||||
|
||||
v2 = os.environ.get("MDNS_TIMEOUT", None)
|
||||
MDNS_TIMEOUT = int(v2) if v2 is not None else None
|
||||
v = os.environ.get("MDNS_TIMEOUT", None)
|
||||
MDNS_TIMEOUT = int(v) if v is not None else None
|
||||
if MDNS_TIMEOUT is not None:
|
||||
dbg(f"Avahi request timeout: {MDNS_TIMEOUT}")
|
||||
|
||||
|
@ -824,139 +563,6 @@ def operate(id, event, qstate, qdata) -> bool:
|
|||
|
||||
n2: str = name.rstrip(".")
|
||||
|
||||
if NFT_TOKEN and n2.endswith(f"{NFT_TOKEN}"):
|
||||
if n2.endswith(f".{NFT_TOKEN}"):
|
||||
n3 = n2.removesuffix(f".{NFT_TOKEN}")
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if v["dynamic"] and n3.endswith(f".{k}"):
|
||||
n4 = n3.removesuffix(f".{k}")
|
||||
qdomains = v["domains"]
|
||||
if not lookup_domain(qdomains, n4):
|
||||
add_split_domain(qdomains, n4.split("."))
|
||||
old = []
|
||||
if os.path.exists(f"/var/lib/unbound/{k}_domains.json"):
|
||||
with open(f"/var/lib/unbound/{k}_domains.json", "rt") as f:
|
||||
old = json.load(f)
|
||||
os.rename(
|
||||
f"/var/lib/unbound/{k}_domains.json",
|
||||
f"/var/lib/unbound/{k}_domains.json.bak",
|
||||
)
|
||||
old.append(n4)
|
||||
with open(f"/var/lib/unbound/{k}_domains.json", "wt") as f:
|
||||
json.dump(old, f)
|
||||
elif n2.endswith(f".tmp{NFT_TOKEN}"):
|
||||
n3 = n2.removesuffix(f".tmp{NFT_TOKEN}")
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if v["dynamic"] and n3.endswith(f".{k}"):
|
||||
n4 = n3.removesuffix(f".{k}")
|
||||
qdomains = v["domains"]
|
||||
if not lookup_domain(qdomains, n4):
|
||||
add_split_domain(qdomains, n4.split("."))
|
||||
return True
|
||||
qnames: list[str] = []
|
||||
for k, v in NFT_QUERIES.items():
|
||||
if lookup_domain(v["domains"], n2):
|
||||
qnames.append(k)
|
||||
# THIS IS PAIN
|
||||
if qnames:
|
||||
try:
|
||||
ip4: list[str] = []
|
||||
ip6: list[str] = []
|
||||
if qstate.return_msg and qstate.return_msg.rep:
|
||||
rep = qstate.return_msg.rep
|
||||
for i in range(rep.rrset_count):
|
||||
d = rep.rrsets[i].entry.data
|
||||
rk = rep.rrsets[i].rk
|
||||
for j in range(0, d.count + d.rrsig_count):
|
||||
wire = array.array("B", d.rr_data[j]).tobytes()
|
||||
# IN
|
||||
if rk.rrset_class != 256:
|
||||
continue
|
||||
# A, AAAA
|
||||
if (
|
||||
rk.type == 256
|
||||
and len(wire) == 4 + 2
|
||||
and wire[:2] == b"\x00\x04"
|
||||
):
|
||||
ip4.append(".".join(str(x) for x in wire[2:]))
|
||||
elif (
|
||||
rk.type == 7168
|
||||
and len(wire) == 16 + 2
|
||||
and wire[:2] == b"\x00\x10"
|
||||
):
|
||||
b = list(hex(x)[2:].zfill(2) for x in wire[2:])
|
||||
ip6.append(
|
||||
":".join(
|
||||
"".join(b[x : x + 2]) for x in range(0, len(b), 2)
|
||||
)
|
||||
)
|
||||
|
||||
changed4 = False
|
||||
changed6 = False
|
||||
if ip4:
|
||||
new_data = "\n".join(sorted(ip4))
|
||||
try:
|
||||
with open("/var/lib/unbound/domains4/" + n2, "rt") as f:
|
||||
old_data = f.read()
|
||||
except:
|
||||
old_data = ""
|
||||
if old_data != new_data:
|
||||
changed4 = True
|
||||
with open("/var/lib/unbound/domains4/" + n2, "wt") as f:
|
||||
f.write(new_data)
|
||||
if ip6:
|
||||
new_data = "\n".join(sorted(ip6))
|
||||
try:
|
||||
with open("/var/lib/unbound/domains6/" + n2, "rt") as f:
|
||||
old_data = f.read()
|
||||
except:
|
||||
old_data = ""
|
||||
if old_data != new_data:
|
||||
changed6 = True
|
||||
with open("/var/lib/unbound/domains6/" + n2, "wt") as f:
|
||||
f.write(new_data)
|
||||
if changed4:
|
||||
for qname in qnames:
|
||||
q = NFT_QUERIES[qname]
|
||||
name4 = q["name4"]
|
||||
ips4 = q["ips4"]
|
||||
if name4:
|
||||
ip2 = []
|
||||
for ip in ip4:
|
||||
exists = False
|
||||
try:
|
||||
if ips4.has_key(ip) or ips4.parent(ip) != None:
|
||||
exists = True
|
||||
except:
|
||||
pass
|
||||
if not exists:
|
||||
ips4.insert(ip, None)
|
||||
ip2.append(ip)
|
||||
if ip2:
|
||||
add_ips(name4, False, ip2)
|
||||
if changed6:
|
||||
for qname in qnames:
|
||||
q = NFT_QUERIES[qname]
|
||||
name6 = q["name6"]
|
||||
ips6 = q["ips6"]
|
||||
if name6:
|
||||
ip2 = []
|
||||
for ip in ip6:
|
||||
exists = False
|
||||
try:
|
||||
if ips6.has_key(ip) or ips6.parent(ip) != None:
|
||||
exists = True
|
||||
except:
|
||||
pass
|
||||
if not exists:
|
||||
ips6.insert(ip, None)
|
||||
ip2.append(ip)
|
||||
if ip2:
|
||||
add_ips(name6, True, ip2)
|
||||
except:
|
||||
with open("/var/lib/unbound/error.log", "at") as f:
|
||||
traceback.print_exc(file=f)
|
||||
|
||||
if event == MODULE_EVENT_NEW or event == MODULE_EVENT_PASS:
|
||||
qstate.ext_state[id] = MODULE_WAIT_MODULE
|
||||
return True
|
||||
|
@ -1031,13 +637,11 @@ def operate(id, event, qstate, qdata) -> bool:
|
|||
if not m.set_return_msg(qstate):
|
||||
raise Exception("Error in set_return_msg")
|
||||
|
||||
# For some reason this breaks everything! Unbound responds with SERVFAIL instead of using the cache
|
||||
# i.e. the first response is fine, but loading it from cache just doesn't work
|
||||
# Resolution via Avahi works fast anyway so whatever
|
||||
# if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
|
||||
# raise Exception("Error in storeQueryInCache")
|
||||
|
||||
qstate.return_msg.rep.security = 2
|
||||
|
||||
if not storeQueryInCache(qstate, qstate.return_msg.qinfo, qstate.return_msg.rep, 0):
|
||||
raise Exception("Error in storeQueryInCache")
|
||||
|
||||
qstate.return_rcode = Rcode.NOERROR
|
||||
return True
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
, lib
|
||||
, router-lib
|
||||
, server-config
|
||||
, ... }:
|
||||
, ...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.router-settings;
|
||||
|
@ -473,8 +474,8 @@ in {
|
|||
gateways = [ netAddresses.lan6 ];
|
||||
radvdSettings.AdvAutonomous = true;
|
||||
coreradSettings.autonomous = true;
|
||||
# don't allocate addresses for most devices
|
||||
keaSettings.pools = [ ];
|
||||
# # don't allocate addresses for most devices
|
||||
# keaSettings.pools = [ ];
|
||||
# just assign the reservations
|
||||
keaSettings.reservations = map (res:
|
||||
(if res.duid != null then { duid = res.duid; } else { hw-address = res.macAddress; }) // {
|
||||
|
@ -597,20 +598,21 @@ in {
|
|||
[(is.eq ip.saddr "@block4") (log "block4/s ") drop]
|
||||
[(is.eq ip6.saddr "@block6") (log "block6/s ") drop]
|
||||
# default to no vpn...
|
||||
[(mangle meta.mark wan_table)]
|
||||
# # default to vpn...
|
||||
# [(mangle meta.mark vpn_table)]
|
||||
# [(mangle meta.mark wan_table)]
|
||||
# default to vpn...
|
||||
[(mangle meta.mark vpn_table)]
|
||||
[(is.eq meta.mark 0)]
|
||||
# ...but unvpn traffic to/from force_unvpn4/force_unvpn6
|
||||
[(is.eq ip.daddr "@force_unvpn4") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip6.daddr "@force_unvpn6") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip.saddr "@force_unvpn4") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip6.saddr "@force_unvpn6") (mangle meta.mark wan_table)]
|
||||
# ...force vpn to/from force_vpn4/force_vpn6
|
||||
# (disable this if it breaks some sites)
|
||||
[(is.eq ip.daddr "@force_vpn4") (mangle meta.mark vpn_table)]
|
||||
[(is.eq ip6.daddr "@force_vpn6") (mangle meta.mark vpn_table)]
|
||||
[(is.eq ip.saddr "@force_vpn4") (mangle meta.mark vpn_table)]
|
||||
[(is.eq ip6.saddr "@force_vpn6") (mangle meta.mark vpn_table)]
|
||||
# ...but unvpn traffic to/from force_unvpn4/force_unvpn6
|
||||
[(is.eq ip.daddr "@force_unvpn4") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip6.daddr "@force_unvpn6") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip.saddr "@force_unvpn4") (mangle meta.mark wan_table)]
|
||||
[(is.eq ip6.saddr "@force_unvpn6") (mangle meta.mark wan_table)]
|
||||
# block requests to port 25 from hosts other than the server so they can't send mail pretending to originate from my domain
|
||||
# only do this for lans since traffic from other interfaces isn't forwarded to wan
|
||||
[(is.eq meta.iifname lanSet) (is.ne ether.saddr cfg.serverMac) (is.eq meta.l4proto (f: f.tcp)) (is.eq tcp.dport 25) (log "smtp ") drop]
|
||||
|
@ -856,7 +858,7 @@ in {
|
|||
access-control = [ "${netCidrs.netns4} allow" "${netCidrs.netns6} allow" "${netCidrs.lan4} allow" "${netCidrs.lan6} allow" ];
|
||||
aggressive-nsec = true;
|
||||
do-ip6 = true;
|
||||
module-config = ''"validator python iterator"'';
|
||||
module-config = ''"validator dynlib python iterator"'';
|
||||
local-zone = [
|
||||
# incompatible with avahi resolver
|
||||
# ''"local." static''
|
||||
|
@ -888,6 +890,7 @@ in {
|
|||
# normally it would refer to the flake path, but then the service changes on every flake update
|
||||
# instead, write a new file in nix store
|
||||
python.python-script = builtins.toFile "avahi-resolver-v2.py" (builtins.readFile ./avahi-resolver-v2.py);
|
||||
dynlib.dynlib-file = "${pkgs.unbound-mod}/lib/libunbound_mod.so";
|
||||
remote-control.control-enable = true;
|
||||
};
|
||||
};
|
||||
|
@ -907,7 +910,7 @@ in {
|
|||
networking.hosts."${serverAddress6}" = hosted-domains;
|
||||
systemd.services.unbound = lib.mkIf config.services.unbound.enable {
|
||||
environment.PYTHONPATH = let
|
||||
unbound-python = pkgs.python3.withPackages (ps: with ps; [ pydbus dnspython requests pytricia nftables ]);
|
||||
unbound-python = pkgs.python3.withPackages (ps: with ps; [ pydbus dnspython ]);
|
||||
in
|
||||
"${unbound-python}/${unbound-python.sitePackages}";
|
||||
# see https://github.com/NixOS/nixpkgs/pull/310514
|
||||
|
|
|
@ -78,6 +78,8 @@ in {
|
|||
{ directory = /var/lib/certspotter; user = "certspotter"; group = "certspotter"; mode = "0755"; }
|
||||
] ++ lib.optionals (config.services.coop-fd.enable or false) [
|
||||
{ directory = /var/lib/private/coop-fd; mode = "0750"; defaultPerms.mode = "0700"; }
|
||||
] ++ lib.optionals config.virtualisation.docker.enable [
|
||||
{ directory = /var/lib/docker; user = "root"; group = "root"; mode = "0710"; }
|
||||
] ++ lib.optionals config.services.dovecot2.enable [
|
||||
{ directory = /var/lib/dhparams; user = "root"; group = "root"; mode = "0755"; }
|
||||
{ directory = /var/lib/dovecot; user = "root"; group = "root"; mode = "0755"; }
|
||||
|
|
Loading…
Reference in a new issue