/* * Implements the loop checking when a new display is conected/disconnected * which was done in bash. * * # Loop forever looking for 'disconnect' to 'connect' transitions. * until [ -z 1 ] * do * sleep 3 * * # Get new state. * RES=`xrandr -q | grep "$SCREEN_TOP connected"` * if [ "$RES" != "" ] * then * NEW_STATE="connected" * else * NEW_STATE="disconnected" * fi * * # Activate output when state change detected. * if( [ "$OLD_STATE" == "disconnected" ] && [ "$NEW_STATE" == "connected" ]) * then * xrandr --output $SCREEN_TOP --auto --rotate normal --pos 0x0 --output $SCREEN_BOTTOM --auto --rotate normal --below $SCREEN_TOP * fi * * # Save new state * OLD_STATE=$NEW_STATE * done * */ #include #include #include #include #include #include #include #include #include #include #define OCNE(X) ((XRROutputChangeNotifyEvent*)X) #define BUFFER_SIZE 128 #define SCREEN_TOP 0 #define SCREEN_BOTTOM 1 #define NUM_SCREENS 2 // Flag to exit. static int done = 0; // Connections to check. static char *screens[NUM_SCREENS]; // Connections state. static Connection curr_con_state[NUM_SCREENS]; static Connection last_con_state[NUM_SCREENS]; // Command to configure screens. static char *xrandr_cmd[15] = { "/usr/bin/xrandr", "--output", NULL, //$SCREEN_TOP (2) "--auto", "--rotate", "normal", "--pos", "0x0", "--output", NULL, //$SCREEN_BOTTOM (9) "--auto", "--rotate", "normal", "--below", NULL, //$SCREEN_TOP (14) }; void sigint_handler(int sig) { printf( "Ctrl+C received, exiting...\n" ); done = 1; } void UpdateConnectionState(XRROutputInfo *info) { int idx = -1; // Find affected screen. printf("output: %s ", info->name); for (int i = 0; i < NUM_SCREENS; i++) { if( strcmp(screens[i], info->name) == 0 ) { idx = i; break; } } if (idx == -1) { printf("Not handled!\n"); return; } switch (info->connection) { case RR_Connected: printf("connected\n"); curr_con_state[idx] = RR_Connected; break; case RR_Disconnected: printf("disconnected\n"); curr_con_state[idx] = RR_Disconnected; break; default: printf("unknown\n"); curr_con_state[idx] = RR_UnknownConnection; break; } } int main(int argc, char **argv) { Display *dpy; XRRScreenResources *resources; int screen; // Initialize vars. for (int i = 0; i < NUM_SCREENS; i++) { screens[i] = NULL; curr_con_state[i] = RR_UnknownConnection; last_con_state[i] = RR_UnknownConnection; } // Check arguments. if (argc != 3) { fprintf(stderr, "Usage:\n\t%s \n\n", argv[0]); exit(EXIT_FAILURE); } screens[SCREEN_TOP] = argv[1]; screens[SCREEN_BOTTOM] = argv[2]; // Compose xrandr command. xrandr_cmd[2] = screens[SCREEN_TOP]; xrandr_cmd[9] = screens[SCREEN_BOTTOM]; xrandr_cmd[14] = screens[SCREEN_TOP]; // Set CTRL+C signal handler. signal(SIGINT, sigint_handler); // Open display. if ((dpy = XOpenDisplay(NULL)) == NULL) { fprintf(stderr, "Cannot open display\n"); exit(EXIT_FAILURE); } while (done == 0) { // Get info about available resources. resources = XRRGetScreenResources(dpy, DefaultRootWindow(dpy)); if (resources == NULL) { fprintf(stderr, "Could not get screen resources\n"); exit(EXIT_FAILURE); } // Get screen. screen = DefaultScreen(dpy); printf("Display width %d, height %d\n", DisplayWidth(dpy, screen), DisplayHeight(dpy, screen)); // Update current state. for (int o = 0; o < resources->noutput; o++) { XRROutputInfo *info = XRRGetOutputInfo(dpy, resources, resources->outputs[o]); if (info == NULL) { fprintf(stderr, "could not get output 0x%lx information\n", resources->outputs[o]); continue; } UpdateConnectionState(info); XRRFreeOutputInfo(info); } printf("\n"); // Release resources. XRRFreeScreenResources(resources); // Check when TOP changes from disconnected to connected. if( last_con_state[SCREEN_TOP] == RR_Disconnected && curr_con_state[SCREEN_TOP] == RR_Connected ) { printf("Run xrandr command...\n"); if (fork() == 0) { if (dpy) close(ConnectionNumber(dpy)); setsid(); execvp(xrandr_cmd[0], xrandr_cmd); } } // Update state. for (int i = 0; i < NUM_SCREENS; i++) { last_con_state[i] = curr_con_state[i]; } #if 0 // Process XRandr events. printf("1...\n"); XEvent ev; char buf[BUFFER_SIZE]; XRRSelectInput(dpy, DefaultRootWindow(dpy), RROutputChangeNotifyMask); printf("11...\n"); XSync(dpy, False); printf("111...\n"); XSetIOErrorHandler((XIOErrorHandler) error_handler); while (done == 0) { printf("1111...\n"); if (!XNextEvent(dpy, &ev)) { printf("New event received...\n"); XRROutputInfo *info = XRRGetOutputInfo(OCNE(&ev)->display, resources, OCNE(&ev)->output); if (info == NULL) { fprintf(stderr, "Could not get output info\n"); continue; } snprintf(buf, BUFFER_SIZE, "%s %s", info->name, con_actions[info->connection]); printf("Event: %s %s\n", info->name, con_actions[info->connection]); printf("Time: %lu\n", info->timestamp); if (info->crtc == 0) { printf("Size: %lumm x %lumm\n", info->mm_width, info->mm_height); } else { printf("CRTC: %lu\n", info->crtc); XRRCrtcInfo *crtc = XRRGetCrtcInfo(dpy, resources, info->crtc); if (crtc != NULL) { printf("Size: %dx%d\n", crtc->width, crtc->height); XRRFreeCrtcInfo(crtc); } } /* */ XRRFreeOutputInfo(info); } else { printf("Wait event...\n"); } } #endif sleep(3); } XCloseDisplay(dpy); return EXIT_SUCCESS; }