i3
|
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 }