1 //
2 // pekwm_screenshot.cc for pekwm
3 // Copyright (C) 2021 Claes Nästén <pekdon@gmail.com>
4 //
5 // This program is licensed under the GNU GPL.
6 // See the LICENSE file for more information.
7 //
8 
9 #include "pekwm.hh"
10 
11 #include "Compat.hh"
12 #include "ImageHandler.hh"
13 #include "PImageLoaderPng.hh"
14 #include "Util.hh"
15 #include "X11.hh"
16 
17 #include <iostream>
18 #include <iomanip>
19 #include <sstream>
20 
21 extern "C" {
22 #include <sys/types.h>
23 #include <getopt.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <X11/Xutil.h>
27 }
28 
29 static ImageHandler* _image_handler = nullptr;
30 
31 namespace pekwm
32 {
imageHandler()33 	ImageHandler* imageHandler()
34 	{
35 		return _image_handler;
36 	}
37 }
38 
init(Display * dpy)39 static void init(Display* dpy)
40 {
41 	_image_handler = new ImageHandler();
42 }
43 
cleanup()44 static void cleanup()
45 {
46 	delete _image_handler;
47 }
48 
usage(const char * name,int ret)49 static void usage(const char* name, int ret)
50 {
51 	std::cout << "usage: " << name << " [-dh] [screenshot.png]" << std::endl;
52 	std::cout << "  -d --display dpy    Display" << std::endl;
53 	std::cout << "  -h --help           Display this information" << std::endl;
54 	exit(ret);
55 }
56 
get_screenhot_name(const Geometry & gm)57 static std::string get_screenhot_name(const Geometry& gm)
58 {
59 	time_t t = time(nullptr);
60 	tm tm;
61 	localtime_r(&t, &tm);
62 
63 	std::ostringstream name;
64 	name << "pekwm_screenshot-";
65 	name << std::put_time(&tm, "%Y%m%dT%H%M%S");
66 	name << "-" << gm.width << "x" << gm.height;
67 	name << ".png";
68 	return name.str();
69 }
70 
take_screenshot(const std::string & output)71 static int take_screenshot(const std::string& output)
72 {
73 	Geometry gm = X11::getScreenGeometry();
74 	XImage *ximage = X11::getImage(X11::getRoot(),
75 				       gm.x, gm.y, gm.width, gm.height,
76 				       AllPlanes, ZPixmap);
77 	if (ximage == nullptr) {
78 		std::cerr << "Failed to take a screenshot" << std::endl;
79 		return 1;
80 	}
81 
82 	PImage *image = new PImage(ximage);
83 	X11::destroyImage(ximage);
84 
85 	bool success =
86 		PImageLoaderPng::save(output, image->getData(),
87 				      image->getWidth(), image->getHeight());
88 	return success ? 0 : 1;
89 }
90 
main(int argc,char * argv[])91 int main(int argc, char* argv[])
92 {
93 	const char* display = NULL;
94 
95 	static struct option opts[] = {
96 		{const_cast<char*>("display"), required_argument, nullptr, 'd'},
97 		{const_cast<char*>("help"), no_argument, nullptr, 'h'},
98 		{nullptr, 0, nullptr, 0}
99 	};
100 
101 	int ch;
102 	while ((ch = getopt_long(argc, argv, "d:h", opts, nullptr)) != -1) {
103 		switch (ch) {
104 		case 'd':
105 			display = optarg;
106 			break;
107 		case 'h':
108 			usage(argv[0], 0);
109 			break;
110 		default:
111 			usage(argv[0], 1);
112 			break;
113 		}
114 	}
115 
116 	Display *dpy = XOpenDisplay(display);
117 	if (! dpy) {
118 		std::string actual_display =
119 			display ? display : Util::getEnv("DISPLAY");
120 		std::cerr << "Can not open display!" << std::endl
121 			  << "Your DISPLAY variable currently is set to: "
122 			  << actual_display << std::endl;
123 		return 1;
124 	}
125 
126 	X11::init(dpy, true);
127 	init(dpy);
128 
129 
130 	std::string output;
131 	if (optind < argc) {
132 		output = argv[optind];
133 	} else {
134 		output = get_screenhot_name(X11::getScreenGeometry());
135 	}
136 
137 	int ret = take_screenshot(output);
138 	if (ret) {
139 		std::cerr << "failed to write screenshot to " << output << std::endl;
140 	} else {
141 		std::cout << "screenshot written to " << output << std::endl;
142 	}
143 
144 	cleanup();
145 	X11::destruct();
146 
147 	return ret;
148 }
149