diff --git a/default.nix b/default.nix
index df27166..ec733b2 100644
--- a/default.nix
+++ b/default.nix
@@ -1,5 +1,6 @@
{ pkgs ? import <nixpkgs> { }, ... }:
pkgs.oneko.overrideAttrs (oldAttrs: rec {
- src = ./src;
+ #src = ./src;
+ patches = [ ./scale.diff ];
})
diff --git a/scale.diff b/scale.diff
new file mode 100644
index 0000000..e16248c
--- /dev/null
+++ b/scale.diff
@@ -0,0 +1,241 @@
+diff --git a/oneko.c b/oneko.c
+index d2b81fe..d66cf55 100644
+--- a/oneko.c
++++ b/oneko.c
+@@ -68,6 +68,7 @@ char *Foreground = NULL; /* foreground */
+ char *Background = NULL; /* background */
+ long IntervalTime = 0L; /* time */
+ double NekoSpeed = (double)0; /* speed */
++int ScaleFactor = NOTDEFINED;
+ int IdleSpace = 0; /* idle */
+ int NekoMoyou = NOTDEFINED; /* tora */
+ int NoShape = NOTDEFINED; /* noshape */
+@@ -268,6 +269,52 @@ Animation AnimationPattern[][2] =
+
+ static void NullFunction();
+
++/*
++ * Scales the bitmap.
++ */
++
++char*
++ScaleBitmap(char* inputBitmap)
++{
++ int scaledBitmapWidth = BITMAP_WIDTH * ScaleFactor;
++ int scaledBitmapHeight = BITMAP_HEIGHT * ScaleFactor;
++ int scaledBitmapSize = (scaledBitmapWidth / 8) * scaledBitmapHeight;
++ char* result = malloc(scaledBitmapSize);
++
++ for (int i = 0; i < scaledBitmapSize; i++) {
++ result[i] = 0x00;
++ }
++
++ for (int srcY = 0; srcY < BITMAP_HEIGHT; srcY++) {
++ for (int srcX = 0; srcX < BITMAP_WIDTH; srcX++) {
++ int srcByteOffset = (srcX / 8) + (srcY * BITMAP_WIDTH / 8);
++ int srcBitOffset = (srcX % 8);
++ char bit = inputBitmap[srcByteOffset] >> srcBitOffset & 0x01;
++
++ if (bit != 0) {
++ for (int ySub = 0; ySub < ScaleFactor; ySub++) {
++ int dstY = srcY * ScaleFactor + ySub;
++
++ for (int xSub = 0; xSub < ScaleFactor; xSub += 8) {
++ int dstX = srcX * ScaleFactor + xSub;
++ int dstByteOffset = (dstX / 8) + (dstY * scaledBitmapWidth / 8);
++ int dstBitCount = ScaleFactor - xSub;
++ if (dstBitCount > 8) {
++ dstBitCount = 8;
++ }
++ int dstBitOffset = (dstX % 8);
++ char dstBitMask = ((1 << dstBitCount) - 1) << dstBitOffset;
++
++ result[dstByteOffset] |= dstBitMask;
++ }
++ }
++ }
++ }
++ }
++
++ return result;
++}
++
+ /*
+ * $@%S%C%H%^%C%W%G!<%?!&(JGC $@=i4|2=(J
+ */
+@@ -289,20 +336,28 @@ InitBitmapAndGCs()
+ BitmapGCDataTablePtr->GCCreatePtr != NULL;
+ BitmapGCDataTablePtr++) {
+
++ char* scaledPixelPattern = ScaleBitmap(BitmapGCDataTablePtr->PixelPattern[NekoMoyou]);
++
+ *(BitmapGCDataTablePtr->BitmapCreatePtr)
+ = XCreatePixmapFromBitmapData(theDisplay, theRoot,
+- BitmapGCDataTablePtr->PixelPattern[NekoMoyou],
+- BITMAP_WIDTH, BITMAP_HEIGHT,
++ scaledPixelPattern,
++ BITMAP_WIDTH * ScaleFactor, BITMAP_HEIGHT * ScaleFactor,
+ theForegroundColor.pixel,
+ theBackgroundColor.pixel,
+ DefaultDepth(theDisplay, theScreen));
+
++ free(scaledPixelPattern);
++
+ theGCValues.tile = *(BitmapGCDataTablePtr->BitmapCreatePtr);
+
++ char* scaledMaskPattern = ScaleBitmap(BitmapGCDataTablePtr->MaskPattern[NekoMoyou]);
++
+ *(BitmapGCDataTablePtr->BitmapMasksPtr)
+ = XCreateBitmapFromData(theDisplay, theRoot,
+- BitmapGCDataTablePtr->MaskPattern[NekoMoyou],
+- BITMAP_WIDTH, BITMAP_HEIGHT);
++ scaledMaskPattern,
++ BITMAP_WIDTH * ScaleFactor, BITMAP_HEIGHT * ScaleFactor);
++
++ free(scaledMaskPattern);
+
+ *(BitmapGCDataTablePtr->GCCreatePtr)
+ = XCreateGC(theDisplay, theWindow,
+@@ -368,6 +423,14 @@ GetResources()
+ }
+ }
+
++ if (ScaleFactor == NOTDEFINED) {
++ if ((resource = NekoGetDefault("scale")) != NULL) {
++ if (num = atoi(resource)) {
++ ScaleFactor = num;
++ }
++ }
++ }
++
+ if (IdleSpace == 0) {
+ if ((resource = NekoGetDefault("idle")) != NULL) {
+ if (num = atoi(resource)) {
+@@ -408,6 +471,9 @@ GetResources()
+ if (IntervalTime == 0) {
+ IntervalTime = AnimalDefaultsDataTable[NekoMoyou].time;
+ }
++ if (ScaleFactor == NOTDEFINED) {
++ ScaleFactor = 1;
++ }
+ if (NekoSpeed == (double)0) {
+ NekoSpeed = (double)(AnimalDefaultsDataTable[NekoMoyou].speed);
+ }
+@@ -690,7 +756,7 @@ InitScreen(DisplayName)
+ CWOverrideRedirect;
+
+ theWindow = XCreateWindow(theDisplay, theRoot, 0, 0,
+- BITMAP_WIDTH, BITMAP_HEIGHT,
++ BITMAP_WIDTH * ScaleFactor, BITMAP_HEIGHT * ScaleFactor,
+ 0, theDepth, InputOutput, CopyFromParent,
+ theWindowMask, &theWindowAttributes);
+
+@@ -815,7 +881,7 @@ DrawNeko(x, y, DrawAnime)
+ DontMapped = 0;
+ }
+ XFillRectangle(theDisplay, theWindow, DrawGC,
+- 0, 0, BITMAP_WIDTH, BITMAP_HEIGHT);
++ 0, 0, BITMAP_WIDTH * ScaleFactor, BITMAP_HEIGHT * ScaleFactor);
+ }
+
+ XFlush(theDisplay);
+@@ -835,7 +901,7 @@ void
+ RedrawNeko()
+ {
+ XFillRectangle(theDisplay, theWindow, NekoLastGC,
+- 0, 0, BITMAP_WIDTH, BITMAP_HEIGHT);
++ 0, 0, BITMAP_WIDTH * ScaleFactor, BITMAP_HEIGHT * ScaleFactor);
+
+ XFlush(theDisplay);
+ }
+@@ -915,15 +981,15 @@ IsWindowOver()
+ if (NekoY <= 0) {
+ NekoY = 0;
+ ReturnValue = True;
+- } else if (NekoY >= WindowHeight - BITMAP_HEIGHT) {
+- NekoY = WindowHeight - BITMAP_HEIGHT;
++ } else if (NekoY >= WindowHeight - BITMAP_HEIGHT * ScaleFactor) {
++ NekoY = WindowHeight - BITMAP_HEIGHT * ScaleFactor;
+ ReturnValue = True;
+ }
+ if (NekoX <= 0) {
+ NekoX = 0;
+ ReturnValue = True;
+- } else if (NekoX >= WindowWidth - BITMAP_WIDTH) {
+- NekoX = WindowWidth - BITMAP_WIDTH;
++ } else if (NekoX >= WindowWidth - BITMAP_WIDTH * ScaleFactor) {
++ NekoX = WindowWidth - BITMAP_WIDTH * ScaleFactor;
+ ReturnValue = True;
+ }
+
+@@ -1048,24 +1114,24 @@ CalcDxDy()
+ LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH / 2);
+
+ LargeY = (double)(theTargetAttributes.y
+- + YOffset - NekoY - BITMAP_HEIGHT);
++ + YOffset - NekoY - BITMAP_HEIGHT * ScaleFactor);
+ }
+ else {
+ MouseX = theTargetAttributes.x
+ + theTargetAttributes.width / 2 + XOffset;
+ MouseY = theTargetAttributes.y + YOffset;
+- LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH / 2);
+- LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT);
++ LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH * ScaleFactor / 2);
++ LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT * ScaleFactor);
+ }
+ }
+ else {
+- LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH / 2);
+- LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT);
++ LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH * ScaleFactor / 2);
++ LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT * ScaleFactor);
+ }
+ }
+ else {
+- LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH / 2);
+- LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT);
++ LargeX = (double)(MouseX - NekoX - BITMAP_WIDTH * ScaleFactor / 2);
++ LargeY = (double)(MouseY - NekoY - BITMAP_HEIGHT * ScaleFactor);
+ }
+
+ DoubleLength = LargeX * LargeX + LargeY * LargeY;
+@@ -1120,9 +1186,9 @@ NekoThinkDraw()
+ } else if ((NekoMoveDy < 0 && NekoY <= 0)
+ || (ToFocus && theTarget != None && NekoY > MouseY)){
+ SetNekoState(NEKO_U_TOGI);
+- } else if ((NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT)
++ } else if ((NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT * ScaleFactor)
+ || (ToFocus && theTarget != None
+- && NekoY < MouseY - BITMAP_HEIGHT)){
++ && NekoY < MouseY - BITMAP_HEIGHT * ScaleFactor)){
+ SetNekoState(NEKO_D_TOGI);
+ } else {
+ SetNekoState(NEKO_JARE);
+@@ -1298,8 +1364,8 @@ ProcessNeko()
+
+ /* $@G-$N=i4|2=(J */
+
+- NekoX = (WindowWidth - BITMAP_WIDTH / 2) / 2;
+- NekoY = (WindowHeight - BITMAP_HEIGHT / 2) / 2;
++ NekoX = (WindowWidth - BITMAP_WIDTH * ScaleFactor / 2) / 2;
++ NekoY = (WindowHeight - BITMAP_HEIGHT * ScaleFactor / 2) / 2;
+
+ NekoLastX = NekoX;
+ NekoLastY = NekoY;
+@@ -1438,6 +1504,15 @@ GetArguments(argc, argv, theDisplayName)
+ exit(1);
+ }
+ }
++ else if (strcmp(argv[ArgCounter], "-scale") == 0) {
++ ArgCounter++;
++ if (ArgCounter < argc) {
++ ScaleFactor = atoi(argv[ArgCounter]);
++ } else {
++ fprintf(stderr, "%s: -scale option error.\n", ProgramName);
++ exit(1);
++ }
++ }
+ else if (strcmp(argv[ArgCounter], "-time") == 0) {
+ ArgCounter++;
+ if (ArgCounter < argc) {
|