SVNからのミラー
This commit is contained in:
15
CHANGELOG.md
Normal file
15
CHANGELOG.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# 1.0.1 (2025/02/11)
|
||||||
|
* XenoWMでタイルと中央モードに設定する場合、色の修正
|
||||||
|
|
||||||
|
# 1.0.0 (2025/02/10)
|
||||||
|
* C言語の「uw」とC++の「uw-setter」は1つのC++の「uw」にマージ
|
||||||
|
* モードプルダウンの追加
|
||||||
|
* 起動時間が10万%速めた
|
||||||
|
* 画像を選択したら、枠を見える様に
|
||||||
|
* 全画面モード「-f」の修正
|
||||||
|
* マニュアルページの追加
|
||||||
|
* 中央モード「-c」の修正
|
||||||
|
* 「背景の設置」ボタンの修正
|
||||||
|
|
||||||
|
# 0.1.0 (2024/09/16)
|
||||||
|
* 開始
|
||||||
13
LICENSE.txt
Normal file
13
LICENSE.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright © 2018-2025 by 076.moe
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
|
||||||
|
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||||
|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||||
|
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||||
|
SOFTWARE.
|
||||||
122
Makefile
Normal file
122
Makefile
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
UNAME_S != uname -s
|
||||||
|
UNAME_M != uname -m
|
||||||
|
OS = ${UNAME_S}
|
||||||
|
ARCH = ${UNAME_M}
|
||||||
|
|
||||||
|
.if ${UNAME_S} == "OpenBSD"
|
||||||
|
OS = openbsd
|
||||||
|
.elif ${UNAME_S} == "NetBSD"
|
||||||
|
OS = netbsd
|
||||||
|
.elif ${UNAME_S} == "FreeBSD"
|
||||||
|
OS = freebsd
|
||||||
|
.elif ${UNAME_S} == "Dragonfly"
|
||||||
|
OS = dragonfly
|
||||||
|
.elif ${UNAME_S} == "Linux"
|
||||||
|
OS = linux
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.if ${UNAME_M} == "x86_64"
|
||||||
|
ARCH = amd64
|
||||||
|
.endif
|
||||||
|
|
||||||
|
NAME != cat src/fe/window.cc | grep "name =" | awk '{print $$3}' |\
|
||||||
|
sed "s/\"//g" | sed "s/;//"
|
||||||
|
VERSION != cat src/fe/window.cc | grep "version =" | awk '{print $$3}' |\
|
||||||
|
sed "s/\"//g" | sed "s/;//"
|
||||||
|
|
||||||
|
PREFIX = /usr/local
|
||||||
|
.if ${OS} == "linux"
|
||||||
|
PREFIX = /usr
|
||||||
|
.endif
|
||||||
|
|
||||||
|
CC = c++
|
||||||
|
FILES = main.cc src/uw/*.cc src/fe/*.cc
|
||||||
|
|
||||||
|
.if ${OS} == "openbsd"
|
||||||
|
DEPS = pkg_add fltk jpeg png
|
||||||
|
.elif ${OS} == "netbsd"
|
||||||
|
DEPS = pkgin install fltk libjpeg-turbo png
|
||||||
|
.elif ${OS} == "freebsd"
|
||||||
|
DEPS = pkg install fltk libjpeg-turbo png xorg xcb
|
||||||
|
.endif
|
||||||
|
|
||||||
|
CFLAGS = -std=c++20\
|
||||||
|
-Wall -Wextra -pthread -Wno-non-c-typedef-for-linkage -I/usr/include\
|
||||||
|
-L/usr/lib
|
||||||
|
.if ${OS} == "freebsd" || ${OS} == "openbsd" || ${OS} == "netbsd" || ${OS} == "dragonfly
|
||||||
|
CFLAGS += -I/usr/local/include -L/usr/local/lib
|
||||||
|
.endif
|
||||||
|
.if ${OS} == "netbsd"
|
||||||
|
CFLAGS += -I/usr/X11R7/include -L/usr/X11R7/lib -I/usr/pkg/include -L/usr/pkg/lib
|
||||||
|
.elif ${OS} == "openbsd"
|
||||||
|
CFLAGS += -I/usr/X11R6/include -L/usr/X11R6/lib
|
||||||
|
.endif
|
||||||
|
|
||||||
|
LDFLAGS = -lfltk -lfltk_images -lX11
|
||||||
|
.if ${OS} == "netbsd"
|
||||||
|
LDFLAGS += -lpng16 -ljpeg
|
||||||
|
.endif
|
||||||
|
|
||||||
|
SLIB = -lc++
|
||||||
|
.if ${OS} == "openbsd"
|
||||||
|
SLIB = -lc++abi -lpthread -lm -lc \
|
||||||
|
-lXcursor -lXfixes -lXext -lXft -lfontconfig -lXinerama -lXdmcp -lXau \
|
||||||
|
-lpng -lz -ljpeg -lxcb -lXrender -lexpat -lfreetype
|
||||||
|
.elif ${OS} == "freebsd"
|
||||||
|
SLIB = -lcxxrt -lm -lgcc -lXrender -lXcursor -lXfixes -lXext -lXft -lfontconfig\
|
||||||
|
-lXinerama -lthr -lpng16 -lz -ljpeg -lxcb -lfreetype -lexpat -lXau -lXdmcp\
|
||||||
|
-lbz2 -lbrotlidec -lbrotlicommon
|
||||||
|
.elif ${OS} == "netbsd"
|
||||||
|
SLIB = -lstdc++ -lpthread -lm -lc -lXft -lxcb -lfontconfig -lfreetype\
|
||||||
|
-lXau -lXdmcp -lXcursor -lXrandr -lXext -lXrender -lXfixes -lXinerama -lX11\
|
||||||
|
-lexpat -lz -lbz2 -lgcc
|
||||||
|
.elif ${OS} == "linux"
|
||||||
|
SLIB = -lstdc++ -lgcc -lc -lXft -lXext -lXrender -lfontconfig -lXinerama\
|
||||||
|
-lpng16 -lz -ljpeg -lxcb -lfreetype -lexpat -lXau -lXdmcp -lbz2\
|
||||||
|
-lbrotlidec -lbrotlicommon
|
||||||
|
.endif
|
||||||
|
|
||||||
|
all:
|
||||||
|
${CC} -O3 ${CFLAGS} -o ${NAME}\
|
||||||
|
${FILES} -static ${LDFLAGS} ${SLIB}
|
||||||
|
strip ${NAME}
|
||||||
|
|
||||||
|
depend:
|
||||||
|
${DEPS}
|
||||||
|
|
||||||
|
wrong:
|
||||||
|
${CC} -O3 ${CFLAGS} -o ${NAME}\
|
||||||
|
${FILES} ${LDFLAGS} ${SLIB}
|
||||||
|
strip ${NAME}
|
||||||
|
|
||||||
|
debug:
|
||||||
|
${CC} -g ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf ${NAME}
|
||||||
|
|
||||||
|
dist:
|
||||||
|
mkdir -p ${NAME}-${VERSION} release/src
|
||||||
|
cp -R LICENSE.txt Makefile README.md CHANGELOG.md\
|
||||||
|
main.cc ${NAME}-${VERSION}
|
||||||
|
tar zcfv release/src/${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
|
||||||
|
rm -rf ${NAME}-${VERSION}
|
||||||
|
|
||||||
|
release:
|
||||||
|
mkdir -p release/bin/${VERSION}/${OS}/${ARCH} release/man/${VERSION}
|
||||||
|
${CC} -O3 ${CFLAGS} -o release/bin/${VERSION}/${OS}/${ARCH}/${NAME} ${FILES}\
|
||||||
|
-static ${LDFLAGS} ${SLIB}
|
||||||
|
strip release/bin/${VERSION}/${OS}/${ARCH}/${NAME}
|
||||||
|
cp ${NAME}.1 release/man/${VERSION}
|
||||||
|
|
||||||
|
install:
|
||||||
|
mkdir -p ${DESTDIR}${PREFIX}/bin ${DESTDIR}${PREFIX}/share/man/man1
|
||||||
|
cp -f ${NAME} ${DESTDIR}${PREFIX}/bin
|
||||||
|
chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
|
||||||
|
cp -f ${NAME}.1 ${DESTDIR}${PREFIX}/share/man/man1
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -rf ${DESTDIR}${PREFIX}/bin/${NAME}
|
||||||
|
rm -rf${DESTDIR}${PREFIX}/share/man/man1/${NAME}.1
|
||||||
|
|
||||||
|
.PHONY: all depend wrong debug clean dist release install uninstall
|
||||||
71
README.md
Normal file
71
README.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# uw
|
||||||
|
只の背景変更ツール。
|
||||||
|
|
||||||
|
XorgとFLTK以外、従属ライブラリを使いません。
|
||||||
|
|
||||||
|
## 従属ソフト | Dependensy
|
||||||
|
### OpenBSD
|
||||||
|
```sh
|
||||||
|
doas make deps
|
||||||
|
```
|
||||||
|
|
||||||
|
### NetBSD
|
||||||
|
```sh
|
||||||
|
doas make deps
|
||||||
|
```
|
||||||
|
|
||||||
|
### FreeBSD
|
||||||
|
```sh
|
||||||
|
doas make deps
|
||||||
|
```
|
||||||
|
|
||||||
|
### Void Linux
|
||||||
|
```sh
|
||||||
|
doas xbps-install -S fltk fltk-devel libX11 libX11-devel xcb-util xcb-util-devel libpng libpng-devel libjpeg-turbo libjpeg-turbo-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使い方 | Usage
|
||||||
|
### GUIの起動
|
||||||
|
```sh
|
||||||
|
uw
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLIで背景の変更
|
||||||
|
#### タイル
|
||||||
|
```sh
|
||||||
|
uw -t wallpaper.png
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 中央
|
||||||
|
```sh
|
||||||
|
uw -c wallpaper.png
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 全画面
|
||||||
|
```sh
|
||||||
|
uw -f wallpaper.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## インストールする方法 | Installation
|
||||||
|
### BSD
|
||||||
|
```sh
|
||||||
|
doas make depends
|
||||||
|
make
|
||||||
|
doas make install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Void Linux
|
||||||
|
```sh
|
||||||
|
sudo xbps-install fltk fltk-devel libjpeg-turbo libjpeg-turbo-devel libpng libpng-devel
|
||||||
|
bmake
|
||||||
|
sudo bmake install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alpine Linux
|
||||||
|
```sh
|
||||||
|
sudo apk add fltk fltk-dev libjpeg-turbo libjpeg-turbo-dev libpng libpng-dev
|
||||||
|
bmake
|
||||||
|
sudo bmake install
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
124
main.cc
Normal file
124
main.cc
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#include <FL/Fl.H>
|
||||||
|
#include <FL/Fl_Window.H>
|
||||||
|
#include <FL/Fl_Button.H>
|
||||||
|
#include <FL/Fl_Choice.H>
|
||||||
|
#include <FL/Fl_File_Chooser.H>
|
||||||
|
#include <FL/Fl_Box.H>
|
||||||
|
#include <FL/Fl_Scroll.H>
|
||||||
|
#include <FL/Fl_Image.H>
|
||||||
|
#include <FL/Fl_PNG_Image.H>
|
||||||
|
#include <FL/Fl_JPEG_Image.H>
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
#include "src/fe/theme.hh"
|
||||||
|
#include "src/fe/window.hh"
|
||||||
|
#include "src/fe/widget.hh"
|
||||||
|
#include "src/fe/background.hh"
|
||||||
|
#include "src/fe/thumbnail.hh"
|
||||||
|
|
||||||
|
#include "src/uw/background.hh"
|
||||||
|
|
||||||
|
void thumbnail_cb(Fl_Widget *widget, void *userdata) {
|
||||||
|
(void)widget;
|
||||||
|
const char *filepath = static_cast<const char *>(userdata);
|
||||||
|
if (filepath) {
|
||||||
|
uw::Background b(filepath);
|
||||||
|
b.setWallpaper(uw::Mode::TILE);
|
||||||
|
fe::Widget::getSetButton()->deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(fe::Window w) {
|
||||||
|
std::cout << w.getName() << "-" << w.getVersion() << '\n';
|
||||||
|
std::cout << "usage: " << w.getName() << " " << w.getOptions() << " <image>"
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
fe::Window w;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
std::string tit = w.getName() + " " + w.getVersion();
|
||||||
|
Fl_Window *window =
|
||||||
|
new Fl_Window(w.getWidth(), w.getHeight(), tit.c_str());
|
||||||
|
|
||||||
|
fe::Theme::SetDarkTheme();
|
||||||
|
|
||||||
|
// ボタン
|
||||||
|
fe::Widget::setChooseButton(new Fl_Button(10, 740, 200, 40, "画像を選択"));
|
||||||
|
fe::Widget::setSetButton(new Fl_Button(230, 740, 200, 40, "背景の設置"));
|
||||||
|
fe::Widget::getSetButton()->deactivate();
|
||||||
|
|
||||||
|
// モード選択
|
||||||
|
Fl_Choice *modeChoice = new Fl_Choice(450, 740, 200, 40, "");
|
||||||
|
modeChoice->add("タイル");
|
||||||
|
modeChoice->add("中央");
|
||||||
|
modeChoice->add("全画像");
|
||||||
|
modeChoice->value(0);
|
||||||
|
modeChoice->align(FL_ALIGN_TOP);
|
||||||
|
modeChoice->color(FL_BACKGROUND_COLOR);
|
||||||
|
modeChoice->textcolor(FL_FOREGROUND_COLOR);
|
||||||
|
modeChoice->selection_color(FL_BACKGROUND2_COLOR);
|
||||||
|
fe::Widget::setModeChoice(modeChoice);
|
||||||
|
|
||||||
|
// スクロールウィンドウ
|
||||||
|
fe::Widget::setScroll(new Fl_Scroll(10, 10, 780, 720));
|
||||||
|
fe::Widget::getScroll()->type(Fl_Scroll::VERTICAL);
|
||||||
|
fe::Widget::getScroll()->begin();
|
||||||
|
|
||||||
|
// サムネール
|
||||||
|
fe::Thumbnail thumbnail;
|
||||||
|
thumbnail.init();
|
||||||
|
|
||||||
|
fe::Widget::getScroll()->end();
|
||||||
|
|
||||||
|
// ボタンで選択
|
||||||
|
fe::Widget::getChooseButton()->callback(fe::Background::chooseImageCb,
|
||||||
|
(void *)fe::Widget::getSetButton());
|
||||||
|
fe::Widget::getSetButton()->callback(fe::Background::setWallpaperCb);
|
||||||
|
|
||||||
|
fe::Widget::getScroll()->end();
|
||||||
|
window->end();
|
||||||
|
window->show(argc, argv);
|
||||||
|
|
||||||
|
return Fl::run();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
usage(w);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string modeStr = argv[1];
|
||||||
|
std::string filename = argv[2];
|
||||||
|
|
||||||
|
uw::Mode mode;
|
||||||
|
|
||||||
|
if (modeStr == "-t") mode = uw::TILE;
|
||||||
|
else if (modeStr == "-f") mode = uw::FILL;
|
||||||
|
else if (modeStr == "-c") mode = uw::CENTER;
|
||||||
|
else {
|
||||||
|
usage(w);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
uw::Background background(filename);
|
||||||
|
|
||||||
|
if (!background.setWallpaper(mode)) {
|
||||||
|
std::cerr << "背景を設定に失敗。" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
std::cerr << "エラー: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7988
src/dep/stb_image.hh
Normal file
7988
src/dep/stb_image.hh
Normal file
File diff suppressed because it is too large
Load Diff
60
src/fe/background.cc
Normal file
60
src/fe/background.cc
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include <FL/Fl_File_Chooser.H>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include "background.hh"
|
||||||
|
#include "misc.hh"
|
||||||
|
#include "widget.hh"
|
||||||
|
|
||||||
|
std::string fe::Background::sfp;
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
Background::Background() {}
|
||||||
|
Background::~Background() {}
|
||||||
|
|
||||||
|
uw::Mode Background::getMode() {
|
||||||
|
Fl_Choice *choice = Widget::getModeChoice();
|
||||||
|
if (!choice) return uw::Mode::TILE;
|
||||||
|
|
||||||
|
switch (choice->value()) {
|
||||||
|
case 0: return uw::Mode::TILE;
|
||||||
|
case 1: return uw::Mode::CENTER;
|
||||||
|
case 2: return uw::Mode::FILL;
|
||||||
|
default: return uw::Mode::TILE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Background::chooseImageCb(Fl_Widget *, void *) {
|
||||||
|
const char *homedir = std::getenv("HOME");
|
||||||
|
std::string defpath;
|
||||||
|
|
||||||
|
if (homedir) {
|
||||||
|
std::string userdir = std::string(homedir) + "/.local/share/wallpapers";
|
||||||
|
std::string localusr = "/usr/local/share/wallpapers";
|
||||||
|
std::string sysusr = "/usr/share/wallpapers";
|
||||||
|
|
||||||
|
if (Misc::isExist(userdir)) defpath = userdir;
|
||||||
|
else if (Misc::isExist(localusr)) defpath = localusr;
|
||||||
|
else defpath = sysusr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fl_File_Chooser chooser(defpath.c_str(), "*.{png,jpg}",
|
||||||
|
Fl_File_Chooser::SINGLE, "画像を御選択下さい・・・");
|
||||||
|
chooser.show();
|
||||||
|
|
||||||
|
while (chooser.shown()) Fl::wait();
|
||||||
|
|
||||||
|
if (chooser.value() != nullptr) {
|
||||||
|
setFilename(chooser.value());
|
||||||
|
Widget::getSetButton()->activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Background::setWallpaperCb(Fl_Widget *, void *) {
|
||||||
|
if (!getFilename().empty()) {
|
||||||
|
uw::Background bg(getFilename());
|
||||||
|
bg.setWallpaper(getMode());
|
||||||
|
Widget::getSetButton()->deactivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/fe/background.hh
Normal file
27
src/fe/background.hh
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <FL/Fl_Widget.H>
|
||||||
|
#include <FL/Fl_Choice.H>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../uw/background.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class Background {
|
||||||
|
public:
|
||||||
|
Background();
|
||||||
|
~Background();
|
||||||
|
|
||||||
|
static void chooseImageCb(Fl_Widget *, void *);
|
||||||
|
static void setWallpaperCb(Fl_Widget *, void *);
|
||||||
|
static void modeCHangeCb(Fl_Widget *, void *);
|
||||||
|
|
||||||
|
static std::string getFilename() { return sfp; }
|
||||||
|
static void setFilename(std::string filename) { sfp = filename; }
|
||||||
|
static uw::Mode getMode();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::string sfp;
|
||||||
|
};
|
||||||
|
}
|
||||||
85
src/fe/clickablebox.cc
Normal file
85
src/fe/clickablebox.cc
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#include <FL/fl_draw.H>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "clickablebox.hh"
|
||||||
|
#include "../fe/background.hh"
|
||||||
|
|
||||||
|
fe::ClickableBox *fe::ClickableBox::lastSelected = nullptr;
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
int ClickableBox::handle(int event) {
|
||||||
|
switch (event) {
|
||||||
|
case FL_PUSH:
|
||||||
|
if (!imagePath.empty()) {
|
||||||
|
if (lastSelected && lastSelected != this) {
|
||||||
|
lastSelected->isSelected = false;
|
||||||
|
lastSelected->redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelected = true;
|
||||||
|
lastSelected = this;
|
||||||
|
redraw();
|
||||||
|
|
||||||
|
background = std::make_unique<uw::Background>(imagePath);
|
||||||
|
background->setWallpaper(fe::Background().getMode());
|
||||||
|
alterXinitrc(getImagePath());
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return Fl_Box::handle(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClickableBox::draw() {
|
||||||
|
Fl_Box::draw();
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
fl_color(234, 121, 216);
|
||||||
|
fl_line_style(FL_SOLID, 9);
|
||||||
|
fl_rect(x(), y(), w(), h());
|
||||||
|
fl_line_style(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClickableBox::alterXinitrc(const std::string &npath) {
|
||||||
|
const std::string xinitrc = std::string(getenv("HOME")) + "/.xinitrc";
|
||||||
|
std::ifstream in(xinitrc);
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
std::string line;
|
||||||
|
bool founduw = false;
|
||||||
|
bool addeduw = false;
|
||||||
|
|
||||||
|
std::string modeFlag;
|
||||||
|
switch(fe::Background().getMode()) {
|
||||||
|
case uw::Mode::TILE: modeFlag = "-t"; break;
|
||||||
|
case uw::Mode::CENTER: modeFlag = "-c"; break;
|
||||||
|
case uw::Mode::FILL: modeFlag = "-f"; break;
|
||||||
|
default: modeFlag = "-t"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
if (line.rfind("uw -", 0) == 0) {
|
||||||
|
line = "uw " + modeFlag + " " + npath + " &";
|
||||||
|
founduw = true;
|
||||||
|
}
|
||||||
|
lines.push_back(line);
|
||||||
|
|
||||||
|
if (line.rfind("exec ", 0) == 0 && !founduw && !addeduw) {
|
||||||
|
lines.insert(lines.end() - 1, "uw " + modeFlag + " " + npath + " &");
|
||||||
|
addeduw = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
|
||||||
|
if (!founduw && !addeduw) {
|
||||||
|
lines.push_back("uw " + modeFlag + " " + npath + " &");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream out(xinitrc);
|
||||||
|
for (const auto &eline : lines) {
|
||||||
|
out << eline << std::endl;
|
||||||
|
}
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/fe/clickablebox.hh
Normal file
31
src/fe/clickablebox.hh
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <FL/Fl_Box.H>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../uw/background.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class ClickableBox : public Fl_Box {
|
||||||
|
public:
|
||||||
|
ClickableBox(int X, int Y, int W, int H, const char *L = 0)
|
||||||
|
: Fl_Box(X, Y, W, H, L), imagePath{ "" }, isSelected{ false } {}
|
||||||
|
|
||||||
|
void setImagePath(const std::string &path) { imagePath = path; }
|
||||||
|
std::string getImagePath() const { return imagePath; }
|
||||||
|
|
||||||
|
int handle(int event) override;
|
||||||
|
void draw() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string imagePath;
|
||||||
|
std::unique_ptr<uw::Background> background;
|
||||||
|
bool isSelected;
|
||||||
|
|
||||||
|
static ClickableBox *lastSelected;
|
||||||
|
|
||||||
|
void alterXinitrc(const std::string &npath);
|
||||||
|
};
|
||||||
|
}
|
||||||
11
src/fe/misc.cc
Normal file
11
src/fe/misc.cc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include "misc.hh"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
bool Misc::isExist(const std::string &path) {
|
||||||
|
std::filesystem::path fsPath(path);
|
||||||
|
return std::filesystem::exists(fsPath) && std::filesystem::is_directory(fsPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/fe/misc.hh
Normal file
10
src/fe/misc.hh
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class Misc {
|
||||||
|
public:
|
||||||
|
static bool isExist(const std::string &path);
|
||||||
|
};
|
||||||
|
}
|
||||||
11
src/fe/theme.cc
Normal file
11
src/fe/theme.cc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <FL/Fl.H>
|
||||||
|
|
||||||
|
#include "theme.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
void Theme::SetDarkTheme() {
|
||||||
|
Fl::background(35, 32, 35);
|
||||||
|
Fl::background2(68, 59, 68);
|
||||||
|
Fl::foreground(252, 252, 252);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/fe/theme.hh
Normal file
10
src/fe/theme.hh
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class Theme {
|
||||||
|
public:
|
||||||
|
static void SetDarkTheme();
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
}
|
||||||
186
src/fe/thumbnail.cc
Normal file
186
src/fe/thumbnail.cc
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
#include <FL/Fl.H>
|
||||||
|
#include <FL/Fl_PNG_Image.H>
|
||||||
|
#include <FL/Fl_JPEG_Image.H>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "thumbnail.hh"
|
||||||
|
#include "clickablebox.hh"
|
||||||
|
#include "misc.hh"
|
||||||
|
#include "widget.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
Thumbnail::Thumbnail() : loadingDialog(nullptr) {}
|
||||||
|
|
||||||
|
Thumbnail::~Thumbnail() {
|
||||||
|
for (auto img : thumbs) {
|
||||||
|
delete img;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadingDialog) {
|
||||||
|
delete loadingDialog;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thumbnail::createLoadingDialog() {
|
||||||
|
Fl_Window *mainWindow = Widget::getScroll()->window();
|
||||||
|
if (!mainWindow) return;
|
||||||
|
|
||||||
|
int w = 200;
|
||||||
|
int h = 100;
|
||||||
|
int sw = mainWindow->w();
|
||||||
|
int sh = mainWindow->h();
|
||||||
|
|
||||||
|
int sx = mainWindow->x();
|
||||||
|
int sy = mainWindow->y();
|
||||||
|
int x = sx + (sw - w) / 2;
|
||||||
|
int y = sy + (sh - h) / 2;
|
||||||
|
|
||||||
|
loadingDialog = new Fl_Window(x, y, w, h, "読み込み中");
|
||||||
|
loadingDialog->set_modal();
|
||||||
|
|
||||||
|
Fl_Box *box =
|
||||||
|
new Fl_Box(0, 0, w, h, "画像を読み込んでいます。\nお待ち下さい。");
|
||||||
|
box->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
|
||||||
|
|
||||||
|
loadingDialog->end();
|
||||||
|
loadingDialog->show();
|
||||||
|
loadingDialog->take_focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thumbnail::init() {
|
||||||
|
const char *home = getenv("HOME");
|
||||||
|
std::string homedir = "";
|
||||||
|
if (home) homedir = std::string(home) + "/.local/share/wallpapers";
|
||||||
|
std::string localdir = "/usr/local/share/wallpapers";
|
||||||
|
std::string sysdir = "/usr/share/wallpapers";
|
||||||
|
|
||||||
|
if (Misc::isExist(homedir)) {
|
||||||
|
std::vector<std::string> img = listImages(homedir);
|
||||||
|
imgfiles.insert(imgfiles.end(), img.begin(), img.end());
|
||||||
|
}
|
||||||
|
if (Misc::isExist(localdir)) {
|
||||||
|
std::vector<std::string> img = listImages(localdir);
|
||||||
|
imgfiles.insert(imgfiles.end(), img.begin(), img.end());
|
||||||
|
}
|
||||||
|
if (Misc::isExist(sysdir)) {
|
||||||
|
std::vector<std::string> img = listImages(sysdir);
|
||||||
|
imgfiles.insert(imgfiles.end(), img.begin(), img.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::getScroll()->deactivate();
|
||||||
|
|
||||||
|
for (const auto &file : imgfiles) {
|
||||||
|
pending.push(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
createLoadingDialog();
|
||||||
|
Fl::add_timeout(0.0, loadImagesCb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thumbnail::loadImagesCb(void *v) {
|
||||||
|
Thumbnail *thumb = static_cast<Thumbnail *>(v);
|
||||||
|
thumb->loadNextImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thumbnail::loadNextImage() {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
|
||||||
|
if (pending.empty()) {
|
||||||
|
if (loadingDialog) {
|
||||||
|
loadingDialog->hide();
|
||||||
|
delete loadingDialog;
|
||||||
|
loadingDialog = nullptr;
|
||||||
|
}
|
||||||
|
Widget::getScroll()->activate();
|
||||||
|
Widget::getScroll()->redraw();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string filepath = pending.front();
|
||||||
|
pending.pop();
|
||||||
|
|
||||||
|
Fl_Image *img = nullptr;
|
||||||
|
std::string ext = filepath.substr(filepath.size() - 4);
|
||||||
|
|
||||||
|
if (ext == ".png") {
|
||||||
|
img = new Fl_PNG_Image(filepath.c_str());
|
||||||
|
} else if (ext == ".jpg") {
|
||||||
|
img = new Fl_JPEG_Image(filepath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!img || img->w() <= 0 || img->h() <= 0) {
|
||||||
|
if (img) delete img;
|
||||||
|
if (!pending.empty()) Fl::add_timeout(0.0, loadImagesCb, this);
|
||||||
|
else {
|
||||||
|
if (loadingDialog) {
|
||||||
|
loadingDialog->hide();
|
||||||
|
delete loadingDialog;
|
||||||
|
loadingDialog = nullptr;
|
||||||
|
}
|
||||||
|
Widget::getScroll()->activate();
|
||||||
|
Widget::getScroll()->redraw();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Fl_Image *thumb = img->copy(100, 100);
|
||||||
|
thumbs.push_back(thumb);
|
||||||
|
delete img;
|
||||||
|
|
||||||
|
ClickableBox *box = new ClickableBox(curX, curY, 100, 100);
|
||||||
|
box->image(thumb);
|
||||||
|
box->box(FL_FLAT_BOX);
|
||||||
|
box->setImagePath(filepath.c_str());
|
||||||
|
|
||||||
|
Widget::getScroll()->add(box);
|
||||||
|
Widget::getScroll()->redraw();
|
||||||
|
|
||||||
|
curX += 110;
|
||||||
|
if (curX + 110 > Widget::getScroll()->w()) {
|
||||||
|
curX = 10;
|
||||||
|
curY += 110;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pending.empty()) Fl::add_timeout(0.01, loadImagesCb, this);
|
||||||
|
else {
|
||||||
|
if (loadingDialog) {
|
||||||
|
loadingDialog->hide();
|
||||||
|
delete loadingDialog;
|
||||||
|
loadingDialog = nullptr;
|
||||||
|
}
|
||||||
|
Widget::getScroll()->activate();
|
||||||
|
Widget::getScroll()->redraw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Thumbnail::listImages(const std::string &directory) {
|
||||||
|
std::vector<std::string> images;
|
||||||
|
std::filesystem::path dir(directory);
|
||||||
|
|
||||||
|
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
|
||||||
|
std::cerr << "ディレクトリを開くに失敗: " << directory << std::endl;
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator(dir)) {
|
||||||
|
if (!entry.is_regular_file()) continue;
|
||||||
|
|
||||||
|
std::string filename = entry.path().filename().string();
|
||||||
|
if (filename.size() <= 4) continue;
|
||||||
|
|
||||||
|
std::string ext = entry.path().extension().string();
|
||||||
|
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||||
|
|
||||||
|
if (ext == ".png" || ext == ".jpg") {
|
||||||
|
images.push_back(entry.path().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/fe/thumbnail.hh
Normal file
33
src/fe/thumbnail.hh
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <FL/Fl_Image.H>
|
||||||
|
#include <FL/Fl_Window.H>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class Thumbnail {
|
||||||
|
public:
|
||||||
|
Thumbnail();
|
||||||
|
~Thumbnail();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
static void loadImagesCb(void *v);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> imgfiles;
|
||||||
|
std::vector<Fl_Image *> thumbs;
|
||||||
|
std::queue<std::string> pending;
|
||||||
|
std::mutex mutex;
|
||||||
|
int curX = 10;
|
||||||
|
int curY = 10;
|
||||||
|
Fl_Window *loadingDialog;
|
||||||
|
|
||||||
|
void createLoadingDialog();
|
||||||
|
std::vector<std::string> listImages(const std::string &directory);
|
||||||
|
void loadNextImage();
|
||||||
|
};
|
||||||
|
}
|
||||||
8
src/fe/widget.cc
Normal file
8
src/fe/widget.cc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include "widget.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
Fl_Button *Widget::setButton = nullptr;
|
||||||
|
Fl_Button *Widget::chooseButton = nullptr;
|
||||||
|
Fl_Scroll *Widget::scroll = nullptr;
|
||||||
|
Fl_Choice *Widget::modeChoice = nullptr;
|
||||||
|
}
|
||||||
25
src/fe/widget.hh
Normal file
25
src/fe/widget.hh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <FL/Fl_Button.H>
|
||||||
|
#include <FL/Fl_Scroll.H>
|
||||||
|
#include <FL/Fl_Choice.H>
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
class Widget {
|
||||||
|
public:
|
||||||
|
static Fl_Button *getSetButton() { return setButton; }
|
||||||
|
static void setSetButton(Fl_Button *b) { setButton = b; }
|
||||||
|
static Fl_Button *getChooseButton() { return chooseButton; }
|
||||||
|
static void setChooseButton(Fl_Button *b) { chooseButton = b; }
|
||||||
|
static Fl_Scroll *getScroll() { return scroll; }
|
||||||
|
static void setScroll(Fl_Scroll *s) { scroll = s; }
|
||||||
|
static Fl_Choice *getModeChoice() { return modeChoice; }
|
||||||
|
static void setModeChoice(Fl_Choice *c) { modeChoice = c; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Fl_Button *chooseButton;
|
||||||
|
static Fl_Button *setButton;
|
||||||
|
static Fl_Scroll *scroll;
|
||||||
|
static Fl_Choice *modeChoice;
|
||||||
|
};
|
||||||
|
}
|
||||||
13
src/fe/window.cc
Normal file
13
src/fe/window.cc
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#include "window.hh"
|
||||||
|
|
||||||
|
namespace fe {
|
||||||
|
Window::Window() {
|
||||||
|
width = 800;
|
||||||
|
height = 800;
|
||||||
|
name = "uw";
|
||||||
|
version = "1.0.1";
|
||||||
|
avalopt = "[-cft]";
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::~Window() {}
|
||||||
|
}
|
||||||
23
src/fe/window.hh
Normal file
23
src/fe/window.hh
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
namespace fe {
|
||||||
|
class Window {
|
||||||
|
public:
|
||||||
|
Window();
|
||||||
|
~Window();
|
||||||
|
|
||||||
|
int getWidth() { return width; }
|
||||||
|
int getHeight() { return height; }
|
||||||
|
std::string getName() { return name; }
|
||||||
|
std::string getVersion() { return version; }
|
||||||
|
std::string getOptions() { return avalopt; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
std::string name;
|
||||||
|
std::string version;
|
||||||
|
std::string avalopt;
|
||||||
|
};
|
||||||
|
}
|
||||||
27
src/uw/background.cc
Normal file
27
src/uw/background.cc
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include "background.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
Background::Background(const std::string &filename)
|
||||||
|
: filename(filename), i(s, filename), o(s, i) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Background::~Background() {}
|
||||||
|
|
||||||
|
bool Background::setWallpaper(Mode mode) {
|
||||||
|
if (mode == Mode::FILL) {
|
||||||
|
o.fill();
|
||||||
|
} else if (mode == Mode::CENTER) {
|
||||||
|
o.center();
|
||||||
|
} else if (mode == Mode::TILE) {
|
||||||
|
o.tile();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
XFlush(s.getDisplay());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/uw/background.hh
Normal file
29
src/uw/background.hh
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "screen.hh"
|
||||||
|
#include "orientation.hh"
|
||||||
|
#include "image.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
enum Mode {
|
||||||
|
FILL,
|
||||||
|
CENTER,
|
||||||
|
TILE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Background {
|
||||||
|
public:
|
||||||
|
Background(const std::string &filepath);
|
||||||
|
~Background();
|
||||||
|
|
||||||
|
bool setWallpaper(Mode mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string filename;
|
||||||
|
Screen s;
|
||||||
|
Image i;
|
||||||
|
Orientation o;
|
||||||
|
};
|
||||||
|
}
|
||||||
78
src/uw/image.cc
Normal file
78
src/uw/image.cc
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <string>
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "../dep/stb_image.hh"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "image.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
Image::Image(Screen &screen, const std::string imgPath) : uwScreen{ screen } {
|
||||||
|
if (imgPath.empty()) throw std::runtime_error("画像パスが空です。");
|
||||||
|
|
||||||
|
data = stbi_load(imgPath.c_str(), &width, &height, &chan, 4);
|
||||||
|
if (!data) throw std::runtime_error("画像の読み込みに失敗: " + imgPath);
|
||||||
|
|
||||||
|
imageExtent.width = width;
|
||||||
|
imageExtent.height = height;
|
||||||
|
imagePath = imgPath;
|
||||||
|
|
||||||
|
v = DefaultVisual(screen.getDisplay(), screen.getScreen());
|
||||||
|
|
||||||
|
createDepth();
|
||||||
|
createPixmap();
|
||||||
|
createImage();
|
||||||
|
createGC();
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::~Image() {
|
||||||
|
if (gc) XFreeGC(uwScreen.getDisplay(), gc);
|
||||||
|
if (pm) XFreePixmap(uwScreen.getDisplay(), pm);
|
||||||
|
if (image) XFree(image);
|
||||||
|
if (data) stbi_image_free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::createDepth() {
|
||||||
|
depth = DefaultDepth(uwScreen.getDisplay(), uwScreen.getScreen());
|
||||||
|
|
||||||
|
if (depth != 24 && depth != 32) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"「" + std::to_string(depth) + "」の様な視覚の深さは未対応です。");
|
||||||
|
}
|
||||||
|
|
||||||
|
imageExtent.depth = depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::createPixmap() {
|
||||||
|
pm = XCreatePixmap(uwScreen.getDisplay(), uwScreen.getWindow(), width, height,
|
||||||
|
depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::createImage() {
|
||||||
|
if (depth == 24) {
|
||||||
|
std::vector<uchar> cd(data, data + (width * height * 4));
|
||||||
|
cdata = cd;
|
||||||
|
|
||||||
|
for (int i = 0; i < width * height; i++) {
|
||||||
|
cdata[i * 4 + 0] = data[i * 4 + 2];
|
||||||
|
cdata[i * 4 + 1] = data[i * 4 + 1];
|
||||||
|
cdata[i * 4 + 2] = data[i * 4 + 0];
|
||||||
|
cdata[i * 4 + 3] = data[i * 4 + 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
image = XCreateImage(uwScreen.getDisplay(), v, depth, ZPixmap, 0,
|
||||||
|
(char *)cdata.data(), width, height, 32, 0);
|
||||||
|
} else {
|
||||||
|
image = XCreateImage(uwScreen.getDisplay(), v, depth, ZPixmap, 0,
|
||||||
|
(char *)data, width, height, 32, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!image) throw std::runtime_error("XImageの作成に失敗。");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::createGC() {
|
||||||
|
gc = XCreateGC(uwScreen.getDisplay(), pm, 0, nullptr);
|
||||||
|
if (!gc) throw std::runtime_error("GCの作成に失敗。");
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/uw/image.hh
Normal file
55
src/uw/image.hh
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "screen.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
|
||||||
|
typedef struct Extent3D {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int depth;
|
||||||
|
} Extent3D;
|
||||||
|
|
||||||
|
class Image {
|
||||||
|
public:
|
||||||
|
Image(Screen &screen, const std::string imgPath);
|
||||||
|
~Image();
|
||||||
|
|
||||||
|
Visual *getVisual() { return v; }
|
||||||
|
XImage *getImage() { return image; }
|
||||||
|
GC getGC() { return gc; }
|
||||||
|
Pixmap getPixmap() { return pm; }
|
||||||
|
Extent3D getExtent() { return imageExtent; }
|
||||||
|
uchar *getImageData() { return data; }
|
||||||
|
std::string getImagePath() { return imagePath; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createDepth();
|
||||||
|
void createPixmap();
|
||||||
|
void createImage();
|
||||||
|
void createGC();
|
||||||
|
|
||||||
|
Visual *v;
|
||||||
|
XImage *image;
|
||||||
|
GC gc;
|
||||||
|
Pixmap pm;
|
||||||
|
|
||||||
|
uchar *data = nullptr;
|
||||||
|
std::vector<uchar> cdata;
|
||||||
|
Extent3D imageExtent;
|
||||||
|
int chan;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int depth;
|
||||||
|
std::string imagePath;
|
||||||
|
|
||||||
|
Screen &uwScreen;
|
||||||
|
};
|
||||||
|
}
|
||||||
164
src/uw/orientation.cc
Normal file
164
src/uw/orientation.cc
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "orientation.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
Orientation::Orientation(Screen &screen, Image &image)
|
||||||
|
: uwScreen{ screen }, uwImage{ image } {
|
||||||
|
}
|
||||||
|
|
||||||
|
Orientation::~Orientation() {}
|
||||||
|
|
||||||
|
void Orientation::center() {
|
||||||
|
Pixmap pm = XCreatePixmap(uwScreen.getDisplay(), uwScreen.getWindow(),
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height,
|
||||||
|
uwImage.getExtent().depth);
|
||||||
|
|
||||||
|
XImage *img = XCreateImage(uwScreen.getDisplay(),
|
||||||
|
uwImage.getVisual(), uwImage.getExtent().depth, ZPixmap, 0, nullptr,
|
||||||
|
uwImage.getExtent().width, uwImage.getExtent().height, 32, 0);
|
||||||
|
|
||||||
|
if (!img) throw std::runtime_error("中央にする為にXImageの作成に失敗。");
|
||||||
|
|
||||||
|
std::vector<char>
|
||||||
|
imgData(uwImage.getExtent().width * uwImage.getExtent().height * 4);
|
||||||
|
img->data = imgData.data();
|
||||||
|
|
||||||
|
for (int y = 0; y < uwImage.getExtent().height; y++) {
|
||||||
|
for (int x = 0; x < uwImage.getExtent().width; x++) {
|
||||||
|
int idx = (y * uwImage.getExtent().width + x) * 4;
|
||||||
|
|
||||||
|
uchar blue = uwImage.getImageData()[idx + 2];
|
||||||
|
uchar green = uwImage.getImageData()[idx + 1];
|
||||||
|
uchar red = uwImage.getImageData()[idx + 0];
|
||||||
|
uchar alpha = uwImage.getImageData()[idx + 3];
|
||||||
|
|
||||||
|
ulong pixel = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||||
|
XPutPixel(img, x, y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XSetForeground(uwScreen.getDisplay(), uwImage.getGC(), 0);
|
||||||
|
XFillRectangle(uwScreen.getDisplay(), pm, uwImage.getGC(), 0, 0,
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height);
|
||||||
|
|
||||||
|
int xoff = (uwScreen.getExtent().width - uwImage.getExtent().width) / 2;
|
||||||
|
int yoff = (uwScreen.getExtent().height - uwImage.getExtent().height) / 2;
|
||||||
|
if (xoff < 0) xoff = 0;
|
||||||
|
if (yoff < 0) yoff = 0;
|
||||||
|
|
||||||
|
XPutImage(uwScreen.getDisplay(), pm, uwImage.getGC(), img, 0, 0, xoff, yoff,
|
||||||
|
uwImage.getExtent().width, uwImage.getExtent().height);
|
||||||
|
|
||||||
|
XSetWindowBackgroundPixmap(uwScreen.getDisplay(), uwScreen.getWindow(), pm);
|
||||||
|
XClearWindow(uwScreen.getDisplay(), uwScreen.getWindow());
|
||||||
|
|
||||||
|
XFreePixmap(uwScreen.getDisplay(), pm);
|
||||||
|
img->data = nullptr;
|
||||||
|
XDestroyImage(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orientation::fill() {
|
||||||
|
Pixmap pm = XCreatePixmap(uwScreen.getDisplay(), uwScreen.getWindow(),
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height,
|
||||||
|
uwImage.getExtent().depth);
|
||||||
|
|
||||||
|
XImage *img = XCreateImage(uwScreen.getDisplay(),
|
||||||
|
uwImage.getVisual(), uwImage.getExtent().depth, ZPixmap, 0, nullptr,
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height, 32, 0);
|
||||||
|
|
||||||
|
if (!img) throw std::runtime_error("スケールする為にXImageの作成に失敗。");
|
||||||
|
|
||||||
|
std::vector<char> sdata(
|
||||||
|
uwScreen.getExtent().width * uwScreen.getExtent().height * 4);
|
||||||
|
img->data = sdata.data();
|
||||||
|
if (!img->data)
|
||||||
|
throw std::runtime_error("スケールしたデータにメモリの役割に失敗。");
|
||||||
|
|
||||||
|
double xScale = (double)uwScreen.getExtent().width / uwImage.getExtent().width;
|
||||||
|
double yScale = (double)uwScreen.getExtent().height / uwImage.getExtent().height;
|
||||||
|
|
||||||
|
for (int y = 0; y < uwScreen.getExtent().height; y++) {
|
||||||
|
for(int x = 0; x < uwScreen.getExtent().width; x++) {
|
||||||
|
int srcx = (x / xScale);
|
||||||
|
int srcy = (y / yScale);
|
||||||
|
|
||||||
|
if (srcx >= uwImage.getExtent().width) srcx = uwImage.getExtent().width - 1;
|
||||||
|
if (srcy >= uwImage.getExtent().height) srcy = uwImage.getExtent().height - 1;
|
||||||
|
|
||||||
|
int sidx = (srcy * uwImage.getExtent().width + srcx) * 4;
|
||||||
|
if (sidx >= uwImage.getExtent().width * uwImage.getExtent().height * 4)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uchar blue = uwImage.getImageData()[sidx + 2];
|
||||||
|
uchar green = uwImage.getImageData()[sidx + 1];
|
||||||
|
uchar red = uwImage.getImageData()[sidx + 0];
|
||||||
|
uchar alpha = uwImage.getImageData()[sidx + 3];
|
||||||
|
|
||||||
|
ulong pixel = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||||
|
XPutPixel(img, x, y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XClearWindow(uwScreen.getDisplay(), uwScreen.getWindow());
|
||||||
|
XPutImage(uwScreen.getDisplay(), pm, uwImage.getGC(), img, 0, 0, 0, 0,
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height);
|
||||||
|
|
||||||
|
XSetWindowBackgroundPixmap(uwScreen.getDisplay(), uwScreen.getWindow(), pm);
|
||||||
|
XClearWindow(uwScreen.getDisplay(), uwScreen.getWindow());
|
||||||
|
|
||||||
|
XFreePixmap(uwScreen.getDisplay(), pm);
|
||||||
|
img->data = nullptr;
|
||||||
|
XDestroyImage(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Orientation::tile() {
|
||||||
|
Pixmap pm = XCreatePixmap(uwScreen.getDisplay(), uwScreen.getWindow(),
|
||||||
|
uwScreen.getExtent().width, uwScreen.getExtent().height,
|
||||||
|
uwImage.getExtent().depth);
|
||||||
|
|
||||||
|
XImage *img = XCreateImage(uwScreen.getDisplay(),
|
||||||
|
uwImage.getVisual(), uwImage.getExtent().depth, ZPixmap, 0, nullptr,
|
||||||
|
uwImage.getExtent().width, uwImage.getExtent().height, 32, 0);
|
||||||
|
|
||||||
|
if (!img) throw std::runtime_error("タイルする為にXImageの作成に失敗。");
|
||||||
|
|
||||||
|
std::vector<char>
|
||||||
|
imgData(uwImage.getExtent().width * uwImage.getExtent().height * 4);
|
||||||
|
img->data = imgData.data();
|
||||||
|
|
||||||
|
for (int y = 0; y < uwImage.getExtent().height; y++) {
|
||||||
|
for (int x = 0; x < uwImage.getExtent().width; x++) {
|
||||||
|
int idx = (y * uwImage.getExtent().width + x) * 4;
|
||||||
|
|
||||||
|
uchar blue = uwImage.getImageData()[idx + 2];
|
||||||
|
uchar green = uwImage.getImageData()[idx + 1];
|
||||||
|
uchar red = uwImage.getImageData()[idx + 0];
|
||||||
|
uchar alpha = uwImage.getImageData()[idx + 3];
|
||||||
|
|
||||||
|
ulong pixel = (alpha << 24) | (red << 16) | (green << 8) | blue;
|
||||||
|
XPutPixel(img, x, y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XPutImage(uwScreen.getDisplay(), pm, uwImage.getGC(), img, 0, 0, 0, 0,
|
||||||
|
uwImage.getExtent().width, uwImage.getExtent().height);
|
||||||
|
|
||||||
|
XSetWindowBackgroundPixmap(uwScreen.getDisplay(), uwScreen.getWindow(), pm);
|
||||||
|
XClearWindow(uwScreen.getDisplay(), uwScreen.getWindow());
|
||||||
|
|
||||||
|
for (int y = 0; y < uwScreen.getExtent().height; y += uwImage.getExtent().height) {
|
||||||
|
for (int x = 0; x < uwScreen.getExtent().width; x += uwImage.getExtent().width) {
|
||||||
|
XCopyArea(uwScreen.getDisplay(), pm, uwScreen.getWindow(), uwImage.getGC(),
|
||||||
|
0, 0, uwImage.getExtent().width, uwImage.getExtent().height, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFreePixmap(uwScreen.getDisplay(), pm);
|
||||||
|
img->data = nullptr;
|
||||||
|
XDestroyImage(img);
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/uw/orientation.hh
Normal file
20
src/uw/orientation.hh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "screen.hh"
|
||||||
|
#include "image.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
class Orientation {
|
||||||
|
public:
|
||||||
|
Orientation(Screen &screen, Image &image);
|
||||||
|
~Orientation();
|
||||||
|
|
||||||
|
void center();
|
||||||
|
void fill();
|
||||||
|
void tile();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Screen &uwScreen;
|
||||||
|
Image &uwImage;
|
||||||
|
};
|
||||||
|
}
|
||||||
21
src/uw/screen.cc
Normal file
21
src/uw/screen.cc
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "screen.hh"
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
Screen::Screen() {
|
||||||
|
dp = XOpenDisplay(nullptr);
|
||||||
|
if (dp == nullptr) throw std::runtime_error("X画面を開くに失敗。");
|
||||||
|
|
||||||
|
screen = DefaultScreen(dp);
|
||||||
|
w = RootWindow(dp, screen);
|
||||||
|
extent.width = DisplayWidth(dp, screen);
|
||||||
|
extent.height = DisplayHeight(dp, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen::~Screen() {
|
||||||
|
XCloseDisplay(dp);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/uw/screen.hh
Normal file
29
src/uw/screen.hh
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
namespace uw {
|
||||||
|
typedef struct Extent2D {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} Extent2D;
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
public:
|
||||||
|
Screen();
|
||||||
|
~Screen();
|
||||||
|
|
||||||
|
Display *getDisplay() { return dp; }
|
||||||
|
Window getWindow() { return w; }
|
||||||
|
int getScreen() { return screen; }
|
||||||
|
|
||||||
|
Extent2D &getExtent() { return extent; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Display *dp;
|
||||||
|
Window w;
|
||||||
|
int screen;
|
||||||
|
|
||||||
|
Extent2D extent;
|
||||||
|
};
|
||||||
|
}
|
||||||
23
uw.1
Normal file
23
uw.1
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
.TH UW 1 VERSION
|
||||||
|
.SH NAME
|
||||||
|
uw - Unix Wallpaper
|
||||||
|
.br
|
||||||
|
.B uw
|
||||||
|
[-cft \fI\,image\fR]
|
||||||
|
.SH 説明
|
||||||
|
.PP
|
||||||
|
Unixの背景設定ツールです。
|
||||||
|
.br
|
||||||
|
パラメーターなしで実行すると、GUI版(旧uw-setter)を起動します。
|
||||||
|
.TP
|
||||||
|
\fB\,c\fR \fI\,image\fR
|
||||||
|
画面の中央に背景画像を設定します。
|
||||||
|
.TP
|
||||||
|
\fB\,f\fR \fI\,image\fR
|
||||||
|
画像サイズに関係なく、全画面に背景画像を設定します。
|
||||||
|
.TP
|
||||||
|
\fB\,t\fR \fI\,image\fR
|
||||||
|
画像をタイル状に配置して背景画像を設定します。
|
||||||
|
.SH AUTHORS
|
||||||
|
.PP
|
||||||
|
テクニカル諏訪子(開発者)
|
||||||
Reference in New Issue
Block a user