kbgwm

sucklessy floating window manager
git clone https://git.neuralcrash.com/kbgwm.git
Log | Files | Refs | README | LICENSE

monitor.c (6410B)


      1 /*
      2  * kbgwm, a sucklessy floating window manager
      3  * Copyright (c) 2020-2021, Kebigon <git@kebigon.xyz>
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 
     18 #include "monitor.h"
     19 
     20 #include <stdlib.h>
     21 
     22 #include "list.h"
     23 #include "log.h"
     24 #include "xcbutils.h"
     25 
     26 extern xcb_connection_t *c;
     27 extern xcb_screen_t *screen;
     28 extern const uint_least8_t workspaces_length;
     29 extern struct item *workspaces[];
     30 
     31 int_least16_t randr_base = -1;
     32 struct item *monitors;
     33 
     34 void monitor_add(xcb_randr_output_t, int16_t, int16_t, uint16_t, uint16_t);
     35 struct item *monitor_find_by_id(const xcb_randr_output_t);
     36 
     37 void setup_monitors()
     38 {
     39     const xcb_query_extension_reply_t *extension = xcb_get_extension_data(c, &xcb_randr_id);
     40     if (!extension->present)
     41     {
     42         LOG_WARN("Unable to retrieve the RANDR extension");
     43         return;
     44     }
     45 
     46     monitors_refresh_config();
     47 
     48     randr_base = extension->first_event;
     49     xcb_randr_select_input(
     50         c, screen->root,
     51         XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
     52             XCB_RANDR_NOTIFY_MASK_CRTC_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
     53 }
     54 
     55 void monitor_add(xcb_randr_output_t id, int16_t x, int16_t y, uint16_t width, uint16_t height)
     56 {
     57     LOG_DEBUG_VA("monitor_add: id=%d, x=%d, y=%d, width=%d, height=%d", id, x, y, width, height);
     58 
     59     struct monitor *monitor = emalloc(sizeof(struct monitor));
     60     monitor->id = id;
     61     monitor->x = x;
     62     monitor->y = y;
     63     monitor->width = width;
     64     monitor->height = height;
     65 
     66     list_add(&monitors, monitor);
     67 }
     68 
     69 void monitor_update(struct monitor *monitor, xcb_randr_get_crtc_info_reply_t *crtc)
     70 {
     71     if (crtc->x != monitor->x)
     72         monitor->x = crtc->x;
     73     if (crtc->y != monitor->y)
     74         monitor->y = crtc->y;
     75     if (crtc->width != monitor->width)
     76         monitor->width = crtc->width;
     77     if (crtc->height != monitor->height)
     78         monitor->height = crtc->height;
     79 
     80     // TODO: rearrange clients
     81 }
     82 
     83 void monitor_delete(struct item *mon_item)
     84 {
     85     // Replace the deleted by the next one, or the first one
     86     struct monitor *new_mon = (mon_item->next != NULL ? mon_item->next : monitors)->data;
     87     struct monitor *monitor = list_remove(&monitors, mon_item);
     88 
     89     struct client *client;
     90     struct item *cli_item;
     91 
     92     // move clients to another monitor
     93     for (uint_fast8_t workspace = 0; workspace != workspaces_length; workspace++)
     94     {
     95         for (cli_item = workspaces[workspace]; cli_item != NULL; cli_item = cli_item->next)
     96         {
     97             client = cli_item->data;
     98 
     99             // Not the removed monitor
    100             if (client->monitor->id != monitor->id)
    101                 continue;
    102 
    103             client->monitor = new_mon;
    104             client->x = new_mon->x;
    105             client->y = new_mon->y;
    106 
    107             // Sanitize
    108             client_sanitize_position(client);
    109             client_sanitize_dimensions(client);
    110         }
    111     }
    112 }
    113 
    114 void monitors_refresh_config()
    115 {
    116     const xcb_randr_get_screen_resources_current_cookie_t cookie =
    117         xcb_randr_get_screen_resources_current(c, screen->root);
    118     xcb_randr_get_screen_resources_current_reply_t *res =
    119         xcb_randr_get_screen_resources_current_reply(c, cookie, NULL);
    120     if (NULL == res)
    121     {
    122         LOG_WARN("Unable to retrieve the RANDR screen resources");
    123         return;
    124     }
    125 
    126     int32_t len = xcb_randr_get_screen_resources_current_outputs_length(res);
    127     xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(res);
    128 
    129     int_fast32_t i;
    130 
    131     // Request information for all outputs.
    132     xcb_randr_get_output_info_cookie_t ocookie[len];
    133     for (i = 0; i != len; i++)
    134     {
    135         ocookie[i] = xcb_randr_get_output_info(c, outputs[i], res->config_timestamp);
    136     }
    137 
    138     xcb_randr_get_output_info_reply_t *info;
    139     xcb_randr_get_crtc_info_reply_t *crtc;
    140     struct item *item;
    141 
    142     // Process information replies
    143     for (i = 0; i != len; i++)
    144     {
    145         info = xcb_randr_get_output_info_reply(c, ocookie[i], NULL);
    146         if (info == NULL)
    147             continue;
    148 
    149         // Disabled / disconnected output
    150         if (info->crtc == XCB_NONE || info->connection == XCB_RANDR_CONNECTION_DISCONNECTED)
    151         {
    152             // Already registered monitor -> delete it
    153             if ((item = monitor_find_by_id(outputs[i])) != NULL)
    154             {
    155                 monitor_delete(item);
    156             }
    157 
    158             continue;
    159         }
    160 
    161         crtc = xcb_randr_get_crtc_info_reply(
    162             c, xcb_randr_get_crtc_info(c, info->crtc, res->config_timestamp), NULL);
    163 
    164         // CRTC info not found -> skipping
    165         if (crtc == NULL)
    166             continue;
    167 
    168         // Already registered monitor -> update it
    169         if ((item = monitor_find_by_id(outputs[i])) != NULL)
    170         {
    171             monitor_update(item->data, crtc);
    172         }
    173         // New monitor -> add it to the list
    174         else
    175         {
    176             monitor_add(outputs[i], crtc->x, crtc->y, crtc->width, crtc->height);
    177         }
    178 
    179         free(crtc);
    180         free(info);
    181     }
    182 
    183     free(res);
    184 }
    185 
    186 bool monitor_contains(struct monitor *monitor, uint16_t x, uint16_t y)
    187 {
    188     return monitor->x <= x && x <= monitor->x + monitor->width && //
    189            monitor->y <= y && y <= monitor->y + monitor->height;
    190 }
    191 
    192 // Find a monitor from its id
    193 struct item *monitor_find_by_id(const xcb_randr_output_t id)
    194 {
    195     for (struct item *item = monitors; item != NULL; item = item->next)
    196         if (((struct monitor *)item->data)->id == id)
    197             return item;
    198 
    199     return NULL;
    200 }
    201 
    202 struct item *monitor_find_by_position(const uint16_t x, const uint16_t y)
    203 {
    204     for (struct item *item = monitors; item != NULL; item = item->next)
    205         if (monitor_contains(item->data, x, y))
    206             return item;
    207 
    208     return NULL;
    209 }