1/* 2 * Copyright notice... 3 */ 4 5#include "ctwm.h" 6 7#include <stdio.h> 8#include <stdlib.h> 9#include <string.h> 10#include <X11/extensions/Xrandr.h> 11 12#include "r_area_list.h" 13#include "r_area.h" 14#include "r_layout.h" 15#include "xrandr.h" 16 17 18/** 19 * Use XRANDR to figure out how our monitors are laid out. 20 */ 21RLayout * 22XrandrNewLayout(Display *disp, Window rootw) 23{ 24 int i_nmonitors = 0; 25 XRRMonitorInfo *ps_monitors; 26 char **monitor_names; 27 RAreaList *areas; 28 int evt_base, err_base, ver_maj, ver_min; 29 // XXX *_base and ver_* should move more globally if we start doing 30 // randr stuff anywhere else. 31 32 // If the server doesn't talk RANDR, we have nothing to do. 33 if(XRRQueryExtension(disp, &evt_base, &err_base) != True) { 34 // No RANDR 35#ifdef DEBUG 36 fprintf(stderr, "No RANDR on the server.\n"); 37#endif 38 return NULL; 39 } 40 41 // XRRGetMonitors() wraps the RRGetMonitors request, which requires 42 // 1.5. 43 if(XRRQueryVersion(disp, &ver_maj, &ver_min) == 0) { 44 // Couldn't get the version 45#ifdef DEBUG 46 fprintf(stderr, "Couldn't get server RANDR version.\n"); 47#endif 48 return NULL; 49 } 50 if(ver_maj < 1 || (ver_maj == 1 && ver_min < 5)) { 51#ifdef DEBUG 52 fprintf(stderr, "Server has RANDR %d.%d, we need 1.5+.\n", 53 ver_maj, ver_min); 54#endif 55 return NULL; 56 } 57 58 // RANDR 1.5 function to get info about 'em. 59 ps_monitors = XRRGetMonitors(disp, rootw, 1, &i_nmonitors); 60 if(ps_monitors == NULL || i_nmonitors == 0) { 61 fprintf(stderr, "XRRGetMonitors failed\n"); 62 return NULL; 63 } 64 65 // Useful note: vtwm also apparently has RANDR support. It uses 66 // XRRGetScreenResources() and looping XRRGetCrtcInfo() to load info 67 // about the screen, and its conditionals suggest that's RANDR 1.2. 68 // Look into that if we decide to worry about earlier versions. 69 70 // Add space for all their names (plus trailing NULL) 71 monitor_names = calloc((i_nmonitors + 1), sizeof(char *)); 72 if(monitor_names == NULL) { 73 abort(); 74 } 75 76 // Add each and its name into an RAreaList 77 areas = RAreaListNew(i_nmonitors, NULL); 78 for(int i = 0; i < i_nmonitors; i++) { 79 RArea cur_area = RAreaNew(ps_monitors[i].x, 80 ps_monitors[i].y, 81 ps_monitors[i].width, 82 ps_monitors[i].height); 83 84 char *name = XGetAtomName(disp, ps_monitors[i].name); 85#ifdef DEBUG 86 fprintf(stderr, "NEW area: %s%s", 87 name != NULL ? name : "", 88 name != NULL ? ":" : ""); 89 RAreaPrint(&cur_area); 90 fprintf(stderr, "\n"); 91#endif 92 if(name != NULL) { 93 monitor_names[i] = strdup(name); 94 XFree(name); 95 } 96 else { 97 monitor_names[i] = strdup(""); 98 } 99 100 RAreaListAdd(areas, &cur_area); 101 } 102 103 XRRFreeMonitors(ps_monitors); 104 105 // Build up an RLayout of those areas and their names, and hand it 106 // back. 107 return RLayoutSetMonitorsNames(RLayoutNew(areas), monitor_names); 108} 109