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