├── .clang-format ├── .gitignore ├── Makefile ├── README.md └── clipscreen.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | IndentWidth: 4 3 | AllowShortFunctionsOnASingleLine: false 4 | ColumnLimit: 120 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | clipscreen 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | PKG_DEPS = cairo x11 xext xfixes xrandr 3 | CFLAGS := $(shell pkg-config --cflags $(PKG_DEPS)) -O2 -Wall -Wextra -pedantic 4 | LDFLAGS := $(shell pkg-config --libs $(PKG_DEPS)) 5 | 6 | TARGET = clipscreen 7 | SOURCES = clipscreen.c 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET): $(SOURCES) 12 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 13 | 14 | format: 15 | clang-format -i $(SOURCES) 16 | 17 | clean: 18 | rm -f $(TARGET) 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # clipscreen 2 | 3 | clipscreen is a simple application that creates a virtual monitor that mirrors a portion of your screen. A green rectangle highlights the specified area. 4 | 5 | Why's this useful? You can use any screen sharing tool (Google Meet, Microsoft Teams, Jitsi Meet, etc.) to share the virtual monitor instead of your entire screen. No need to share individual windows and having to switch between them, just move any window you want to share into the green border. 6 | 7 | ## Compile 8 | 9 | Ensure you have the following installed on your system: 10 | 11 | - X11 development libraries 12 | - Cairo graphics library 13 | - A C compiler (e.g., gcc) 14 | 15 | For example, on Ubuntu 24.04, 16 | running `apt-get install libx11-dev xserver-xorg-dev xorg-dev libcairo2-dev gcc` 17 | will install the required libraries. 18 | 19 | Then simply run the following command to compile the application: 20 | 21 | ```bash 22 | make 23 | ``` 24 | 25 | Note: The application has only been tested on Linux and xorg. I doubt it will work on any other system. 26 | 27 | ## Usage 28 | 29 | Run the compiled executable with the following command: 30 | 31 | ```bash 32 | ./clipscreen x++ 33 | ``` 34 | 35 | - ``: The width of the overlay and virtual monitor. 36 | - ``: The height of the overlay and virtual monitor. 37 | - ``: The x-coordinate of the top-left corner of the overlay and virtual monitor. 38 | - ``: The y-coordinate of the top-left corner of the overlay and virtual monitor. 39 | 40 | For example: 41 | 42 | ```bash 43 | ./clipscreen 800x600+100+100 44 | ``` 45 | 46 | This command will create an 800x600 overlay window starting at position (100, 100) on your screen. 47 | 48 | To select an area interactively: 49 | 50 | ```bash 51 | ./clipscreen $(hacksaw) 52 | ``` 53 | 54 | or 55 | 56 | ```bash 57 | ./clipscreen $(slop) 58 | ``` 59 | 60 | With this command, you will be able to select a portion of the screen interactively. 61 | 62 | ## Termination 63 | 64 | To terminate the application, press `Ctrl+C` in the terminal where the application is running. 65 | 66 | ## Links 67 | 68 | * [hacksaw](https://github.com/neXromancers/hacksaw) 69 | * [slop](https://github.com/naelstrof/slop) 70 | 71 | ## License 72 | 73 | Copyright 2024 Andreas Gohr 74 | 75 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 76 | 77 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 78 | 79 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 80 | -------------------------------------------------------------------------------- /clipscreen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | /** 15 | * @brief Draws a green rectangle on the given Cairo context. 16 | * 17 | * @param cr The Cairo context to draw on. 18 | * @param w The width of the rectangle. 19 | * @param h The height of the rectangle. 20 | */ 21 | void draw_rectangle(cairo_t *cr, int w, int h) { 22 | cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.5); 23 | cairo_rectangle(cr, 0, 0, w, h); 24 | cairo_set_line_width(cr, 10.0); 25 | cairo_stroke(cr); 26 | } 27 | 28 | /** 29 | * @brief Removes the virtual monitor from the display. 30 | * 31 | * Deletes the virtual monitor named "clipscreen" if it exists. 32 | * 33 | * @param display The display connection. 34 | * @param root The root window. 35 | */ 36 | void remove_monitor(Display *display, Window root) { 37 | int numMonitors; 38 | XRRMonitorInfo *monitors = XRRGetMonitors(display, root, True, &numMonitors); 39 | 40 | for (int i = 0; i < numMonitors; ++i) { 41 | if (strcmp(XGetAtomName(display, monitors[i].name), "clipscreen") == 0) { 42 | XRRDeleteMonitor(display, root, monitors[i].name); 43 | printf("Removed virtual monitor\n"); 44 | break; 45 | } 46 | } 47 | 48 | XFree(monitors); 49 | } 50 | 51 | /** 52 | * @brief Adds a virtual monitor to the display. 53 | * 54 | * Creates a virtual monitor with the specified dimensions and position. 55 | * 56 | * The created monitor will be 10px smaller than specified to not overlap with the window border. 57 | * 58 | * @param d The display connection. 59 | * @param root The root window. 60 | * @param w The width of the monitor. 61 | * @param h The height of the monitor. 62 | * @param x The x-coordinate of the monitor. 63 | * @param y The y-coordinate of the monitor. 64 | */ 65 | void add_monitor(Display *d, Window root, int w, int h, int x, int y) { 66 | // remove any leftover virtual monitor 67 | remove_monitor(d, root); 68 | 69 | RROutput primary_output = XRRGetOutputPrimary(d, root); 70 | 71 | // Create virtual monitor (equivalent to xrandr --setmonitor) 72 | XRRMonitorInfo monitor; 73 | monitor.name = XInternAtom(d, "clipscreen", False); 74 | monitor.x = x + 5; 75 | monitor.y = y + 5; 76 | monitor.width = w - 10; 77 | monitor.height = h - 10; 78 | monitor.mwidth = w - 10; // Aspect ratio 1/1 79 | monitor.mheight = h - 10; // Aspect ratio 1/1 80 | monitor.noutput = 0; // Output 0 is none 81 | monitor.outputs = &primary_output; 82 | 83 | XRRSetMonitor(d, root, &monitor); 84 | printf("Added virtual monitor\n"); 85 | } 86 | 87 | /** 88 | * @brief Creates an overlay window on the display. 89 | * 90 | * Sets up an overlay window with the specified dimensions and position. 91 | * 92 | * @param d The display connection. 93 | * @param root The root window. 94 | * @param vinfo The X visuals 95 | * @param w The width of the overlay. 96 | * @param h The height of the overlay. 97 | * @param x The x-coordinate of the overlay. 98 | * @param y The y-coordinate of the overlay. 99 | * @return Window The created overlay window. 100 | */ 101 | Window create_overlay_window(Display *d, Window root, XVisualInfo vinfo, int w, int h, int x, int y) { 102 | XSetWindowAttributes attrs; 103 | attrs.override_redirect = true; 104 | 105 | attrs.colormap = XCreateColormap(d, root, vinfo.visual, AllocNone); 106 | attrs.background_pixel = 0; 107 | attrs.border_pixel = 0; 108 | 109 | Window overlay = XCreateWindow(d, root, x, y, w, h, 0, vinfo.depth, InputOutput, vinfo.visual, 110 | CWOverrideRedirect | CWColormap | CWBackPixel | CWBorderPixel, &attrs); 111 | 112 | XRectangle rect; 113 | XserverRegion region = XFixesCreateRegion(d, &rect, 0); 114 | XFixesSetWindowShapeRegion(d, overlay, ShapeInput, 0, 0, region); 115 | XFixesDestroyRegion(d, region); 116 | 117 | XMapWindow(d, overlay); 118 | return overlay; 119 | } 120 | 121 | /** 122 | * @brief Parses the geometry from the command-line arguments. 123 | * 124 | * Sets the width, height, x, and y accordingly and ensures a minimum size of 100x100. 125 | * 126 | * Exits on errors. 127 | * 128 | * @param argc The number of command-line arguments. 129 | * @param argv The array of command-line arguments. 130 | * @param w The width of the window. 131 | * @param h The height of the window. 132 | * @param x The x-coordinate of the window. 133 | * @param y The y-coordinate of the window. 134 | */ 135 | void initGeometry(int argc, char *argv[], unsigned int *w, unsigned int *h, int *x, int *y) { 136 | if (argc > 2 || argc <= 1) { 137 | fprintf(stderr, "Usage: %s x++ (e.g. 800x600+100+100)\n", argv[0]); 138 | exit(EXIT_FAILURE); 139 | } 140 | 141 | int ret = XParseGeometry(argv[1], x, y, w, h); 142 | if (ret == 0) { 143 | fprintf(stderr, "invalid geometry: %s (e.g. 800x600+100+100)\n", argv[1]); 144 | exit(EXIT_FAILURE); 145 | } 146 | 147 | // ensure minimum size so that we can draw a border around something 148 | if (*w < 100) { 149 | fprintf(stderr, "Auto adjusted width\n"); 150 | *w = 100; 151 | } 152 | if (*h < 100) { 153 | fprintf(stderr, "Auto adjusted height\n"); 154 | *h = 100; 155 | } 156 | } 157 | 158 | /** 159 | * @brief Main function for the clipscreen application. 160 | * 161 | * Sets up a virtual monitor and draws a rectangle around it. Waits for SIGINT to terminate. 162 | * 163 | * @param argc The number of command-line arguments. 164 | * @param argv The array of command-line arguments. 165 | * @return int Exit status. 166 | */ 167 | int main(int argc, char *argv[]) { 168 | unsigned int w = 0; 169 | unsigned int h = 0; 170 | int x = 0; 171 | int y = 0; 172 | 173 | // parse geometry from arguments 174 | initGeometry(argc, argv, &w, &h, &x, &y); 175 | 176 | // set up X11 177 | Display *d = XOpenDisplay(NULL); 178 | Window root = DefaultRootWindow(d); 179 | 180 | // add virtual monitor 181 | add_monitor(d, root, w, h, x, y); 182 | 183 | // Initialize Visuals and check for 32 bit color support 184 | XVisualInfo vinfo; 185 | if (!XMatchVisualInfo(d, DefaultScreen(d), 32, TrueColor, &vinfo)) { 186 | printf("No visual found supporting 32 bit color, terminating\n"); 187 | exit(EXIT_FAILURE); 188 | } 189 | 190 | // create overlay border 191 | Window overlay = create_overlay_window(d, root, vinfo, w, h, x, y); 192 | cairo_surface_t *surf = cairo_xlib_surface_create(d, overlay, vinfo.visual, w, h); 193 | cairo_t *cr = cairo_create(surf); 194 | draw_rectangle(cr, w, h); 195 | XFlush(d); 196 | 197 | // wait for SIGINT or SIGTERM 198 | printf("Press Ctrl-C to exit\n"); 199 | int sig; 200 | sigset_t sigset; 201 | sigemptyset(&sigset); 202 | sigaddset(&sigset, SIGINT); 203 | sigaddset(&sigset, SIGTERM); 204 | sigprocmask(SIG_BLOCK, &sigset, NULL); 205 | sigwait(&sigset, &sig); 206 | 207 | // clean up 208 | remove_monitor(d, root); 209 | cairo_destroy(cr); 210 | cairo_surface_destroy(surf); 211 | XUnmapWindow(d, overlay); 212 | XCloseDisplay(d); 213 | return 0; 214 | } 215 | --------------------------------------------------------------------------------