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