• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

src/xinerama.c

Go to the documentation of this file.
00001 /*
00002  * vim:ts=8:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  *
00006  * © 2009-2010 Michael Stapelberg and contributors
00007  *
00008  * See file LICENSE for license information.
00009  *
00010  * This is LEGACY code (we support RandR, which can do much more than
00011  * Xinerama), but necessary for the poor users of the nVidia binary
00012  * driver which does not support RandR in 2010 *sigh*.
00013  *
00014  */
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 
00019 #include <xcb/xcb.h>
00020 #include <xcb/xinerama.h>
00021 
00022 #include "queue.h"
00023 #include "data.h"
00024 #include "util.h"
00025 #include "xinerama.h"
00026 #include "workspace.h"
00027 #include "log.h"
00028 #include "randr.h"
00029 
00030 static int num_screens;
00031 
00032 /*
00033  * Looks in outputs for the Output whose start coordinates are x, y
00034  *
00035  */
00036 static Output *get_screen_at(int x, int y) {
00037         Output *output;
00038         TAILQ_FOREACH(output, &outputs, outputs)
00039                 if (output->rect.x == x && output->rect.y == y)
00040                         return output;
00041 
00042         return NULL;
00043 }
00044 
00045 /*
00046  * Gets the Xinerama screens and converts them to virtual Outputs (only one screen for two
00047  * Xinerama screen which are configured in clone mode) in the given screenlist
00048  *
00049  */
00050 static void query_screens(xcb_connection_t *conn) {
00051         xcb_xinerama_query_screens_reply_t *reply;
00052         xcb_xinerama_screen_info_t *screen_info;
00053 
00054         reply = xcb_xinerama_query_screens_reply(conn, xcb_xinerama_query_screens_unchecked(conn), NULL);
00055         if (!reply) {
00056                 ELOG("Couldn't get Xinerama screens\n");
00057                 return;
00058         }
00059         screen_info = xcb_xinerama_query_screens_screen_info(reply);
00060         int screens = xcb_xinerama_query_screens_screen_info_length(reply);
00061 
00062         for (int screen = 0; screen < screens; screen++) {
00063                 Output *s = get_screen_at(screen_info[screen].x_org, screen_info[screen].y_org);
00064                 if (s != NULL) {
00065                         DLOG("Re-used old Xinerama screen %p\n", s);
00066                         /* This screen already exists. We use the littlest screen so that the user
00067                            can always see the complete workspace */
00068                         s->rect.width = min(s->rect.width, screen_info[screen].width);
00069                         s->rect.height = min(s->rect.height, screen_info[screen].height);
00070                 } else {
00071                         s = scalloc(sizeof(Output));
00072                         asprintf(&(s->name), "xinerama-%d", num_screens);
00073                         DLOG("Created new Xinerama screen %s (%p)\n", s->name, s);
00074                         s->active = true;
00075                         s->rect.x = screen_info[screen].x_org;
00076                         s->rect.y = screen_info[screen].y_org;
00077                         s->rect.width = screen_info[screen].width;
00078                         s->rect.height = screen_info[screen].height;
00079                         /* We always treat the screen at 0x0 as the primary screen */
00080                         if (s->rect.x == 0 && s->rect.y == 0)
00081                                 TAILQ_INSERT_HEAD(&outputs, s, outputs);
00082                         else TAILQ_INSERT_TAIL(&outputs, s, outputs);
00083                         num_screens++;
00084                 }
00085 
00086                 DLOG("found Xinerama screen: %d x %d at %d x %d\n",
00087                                 screen_info[screen].width, screen_info[screen].height,
00088                                 screen_info[screen].x_org, screen_info[screen].y_org);
00089         }
00090 
00091         free(reply);
00092 
00093         if (num_screens == 0) {
00094                 ELOG("No screens found. Please fix your setup. i3 will exit now.\n");
00095                 exit(0);
00096         }
00097 }
00098 
00099 /*
00100  * We have just established a connection to the X server and need the initial Xinerama
00101  * information to setup workspaces for each screen.
00102  *
00103  */
00104 void initialize_xinerama(xcb_connection_t *conn) {
00105         if (!xcb_get_extension_data(conn, &xcb_xinerama_id)->present) {
00106                 DLOG("Xinerama extension not found, disabling.\n");
00107                 disable_randr(conn);
00108         } else {
00109                 xcb_xinerama_is_active_reply_t *reply;
00110                 reply = xcb_xinerama_is_active_reply(conn, xcb_xinerama_is_active(conn), NULL);
00111 
00112                 if (reply == NULL || !reply->state) {
00113                         DLOG("Xinerama is not active (in your X-Server), disabling.\n");
00114                         disable_randr(conn);
00115                 } else
00116                         query_screens(conn);
00117 
00118                 FREE(reply);
00119         }
00120 
00121         Output *output;
00122         Workspace *ws;
00123         /* Just go through each active output and associate one workspace */
00124         TAILQ_FOREACH(output, &outputs, outputs) {
00125                 ws = get_first_workspace_for_output(output);
00126                 initialize_output(conn, output, ws);
00127         }
00128 }

Generated on Fri Feb 18 2011 for i3 by  doxygen 1.7.1