ratpoison-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RP] [RFC v3] Add xrandr support


From: Mathieu OTHACEHE
Subject: [RP] [RFC v3] Add xrandr support
Date: Sat, 12 Nov 2016 17:58:24 +0100

Drop deprecated xinerama support and replace it with xrandr.

Signed-off-by: Mathieu OTHACEHE <address@hidden>
---

Hi,

Here is v3, to address Jeremie review and rebase patch on top of recent changes.

Thanks,

Mathieu

Changelog:

v2 :
* Rebase on top of master
v3 :
* Rebase on top of master
* Follow GNU Coding Style
* Switch static inline functions to regular functions.

 configure.ac                 |  21 ++-
 src/Makefile.am              |   8 +-
 src/actions.c                | 337 +++++++++++++++++++-----------------
 src/bar.c                    |   8 +-
 src/communications.c         |  11 +-
 src/communications.h         |   2 +-
 src/data.h                   |  21 ++-
 src/events.c                 |  82 ++++-----
 src/format.c                 |  10 +-
 src/globals.c                |  31 ++--
 src/globals.h                |  13 +-
 src/group.c                  |  18 +-
 src/input.c                  |  10 +-
 src/linkedlist.c             | 139 +++++++++++++++
 src/linkedlist.h             |   6 +
 src/main.c                   |  98 +++--------
 src/manage.c                 |  22 +--
 src/ratpoison.h              |   2 +-
 src/screen.c                 | 404 ++++++++++++++++++++++++++++++-------------
 src/screen.h                 |  21 ++-
 src/split.c                  | 105 ++++++-----
 src/split.h                  |   2 +-
 src/window.c                 |  60 +++----
 src/window.h                 |   1 +
 src/xinerama.c               | 104 -----------
 src/xrandr.c                 | 204 ++++++++++++++++++++++
 src/{xinerama.h => xrandr.h} |  16 +-
 27 files changed, 1069 insertions(+), 687 deletions(-)
 delete mode 100644 src/xinerama.c
 create mode 100644 src/xrandr.c
 rename src/{xinerama.h => xrandr.h} (74%)

diff --git a/configure.ac b/configure.ac
index 7c2bc83..7e101e7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,20 +158,25 @@ AC_CHECK_LIB(X11, XOpenDisplay, [X_LIBS="-lX11 $X_LIBS"],
 
 mysavedCPPFLAGS="$CPPFLAGS"
 CPPFLAGS="$CPPFLAGS $X_CFLAGS"
-AC_CHECK_HEADERS([X11/extensions/Xinerama.h], [], [], [
-#include <X11/Xlib.h>
-])
-CPPFLAGS="$mysavedCPPFLAGS"
-
-mysavedCPPFLAGS="$CPPFLAGS"
-CPPFLAGS="$CPPFLAGS $X_CFLAGS"
 AC_CHECK_HEADERS([X11/XKBlib.h], [], [], [
 #include <X11/Xlib.h>
 ])
 CPPFLAGS="$mysavedCPPFLAGS"
 
 AC_CHECK_LIB(Xext, XMissingExtension, [X_LIBS="-lXext $X_LIBS"],,$X_LIBS 
$X_EXTRA_LIBS)
-AC_CHECK_LIB(Xinerama, XineramaQueryScreens, [X_LIBS="-lXinerama $X_LIBS"; 
AC_DEFINE(HAVE_LIBXINERAMA,1,[Xinerama])],,$X_LIBS $X_EXTRA_LIBS)
+
+AC_ARG_WITH([xrandr],
+[AS_HELP_STRING([--without-xrandr], [Build without xrandr support, even if 
available])],
+[],
+[with_xrandr=yes])
+
+compile_xrandr=no
+AS_IF([test "$with_xrandr" != no],
+[AC_CHECK_LIB(Xrandr, XRRGetScreenResources, [compile_xrandr=yes 
X_LIBS="-lXrandr $X_LIBS" AC_DEFINE(HAVE_LIBXRANDR, 1, [Xrandr])],,$X_LIBS 
$X_EXTRA_LIBS)]
+[])
+
+AM_CONDITIONAL(HAVE_LIBXRANDR, test "$compile_xrandr" = yes)
+
 AC_CHECK_LIB(Xtst, XTestFakeButtonEvent, [X_LIBS="-lXtst $X_LIBS"; 
AC_DEFINE(HAVE_LIBXTST,1,[Xtst])],,$X_LIBS $X_EXTRA_LIBS)
 AC_CHECK_LIB([X11], [XkbKeycodeToKeysym],
   [AC_DEFINE(HAVE_XKBKEYCODETOKEYSYM, 1,
diff --git a/src/Makefile.am b/src/Makefile.am
index 3ba6de3..0daf587 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -70,6 +70,8 @@ ratpoison_SOURCES     = actions.c             \
                        split.c                 \
                        split.h                 \
                        window.c                \
-                       window.h                \
-                       xinerama.c              \
-                       xinerama.h
+                       window.h
+
+if HAVE_LIBXRANDR
+ratpoison_SOURCES += xrandr.c xrandr.h
+endif
diff --git a/src/actions.c b/src/actions.c
index 3aef26b..acfb466 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -477,7 +477,7 @@ push_frame_undo(rp_screen *screen)
 static rp_frame_undo *
 pop_frame_list (struct list_head *undo_list, struct list_head *redo_list)
 {
-  rp_screen *screen = current_screen();
+  rp_screen *screen = rp_current_screen;
   rp_frame_undo *first, *new;
 
   /* Is there something to restore? */
@@ -1038,9 +1038,9 @@ parse_keydesc (char *keydesc, struct rp_key *key)
 static void
 grab_rat (void)
 {
-  XGrabPointer (dpy, current_screen()->root, True, 0,
+  XGrabPointer (dpy, rp_current_screen->root, True, 0,
                 GrabModeAsync, GrabModeAsync,
-                None, current_screen()->rat, CurrentTime);
+                None, rp_current_screen->rat, CurrentTime);
 }
 
 static void
@@ -1282,7 +1282,7 @@ cmd_other (int interactive UNUSED, struct cmdarg **args 
UNUSED)
   rp_window *w;
 
 /*   w = find_window_other (); */
-  w = group_last_window (rp_current_group, current_screen());
+  w = group_last_window (rp_current_group, rp_current_screen);
 
   if (!w)
     return cmdret_new (RET_FAILURE, "%s", MESSAGE_NO_OTHER_WINDOW);
@@ -1410,7 +1410,7 @@ cmd_select (int interactive, struct cmdarg **args)
               if (interactive)
                 {
                   /* show the window list as feedback */
-                  show_bar (current_screen (), defaults.window_fmt);
+                  show_bar (rp_current_screen, defaults.window_fmt);
                   ret = cmdret_new (RET_SUCCESS, NULL);
                 }
               else
@@ -1458,7 +1458,7 @@ cmd_rename (int interactive UNUSED, struct cmdarg **args)
   hook_run (&rp_title_changed_hook);
 
   /* Update the program bar. */
-  update_window_names (current_screen(), defaults.window_fmt);
+  update_window_names (rp_current_screen, defaults.window_fmt);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -1791,45 +1791,48 @@ read_frame (struct sbuf *s,  struct cmdarg **arg)
   int keysym_bufsize = sizeof (keysym_buf);
   unsigned int mod;
   Window *wins;
-  int i, j;
-  rp_frame *cur;
+  int i;
+  rp_frame *cur_frame;
+  rp_screen *cur_screen;
   int frames;
 
   if (s == NULL)
     {
       frames = 0;
-      for (j=0; j<num_screens; j++)
-        frames += num_frames(&screens[j]);
+
+      list_for_each_entry (cur_screen, &rp_screens, node)
+        {
+          frames += num_frames (cur_screen);
+        }
 
       wins = xmalloc (sizeof (Window) * frames);
 
       /* Loop through each frame and display its number in it's top
          left corner. */
       i = 0;
-      for (j=0; j<num_screens; j++)
+      list_for_each_entry (cur_screen, &rp_screens, node)
         {
           XSetWindowAttributes attr;
-          rp_screen *screen = &screens[j];
 
           /* Set up the window attributes to be used in the loop. */
-          attr.border_pixel = screen->fg_color;
-          attr.background_pixel = screen->bg_color;
+          attr.border_pixel = rp_glob_screen.fg_color;
+          attr.background_pixel = rp_glob_screen.bg_color;
           attr.override_redirect = True;
 
-          list_for_each_entry (cur, &screen->frames, node)
+          list_for_each_entry (cur_frame, &cur_screen->frames, node)
             {
               int width, height;
               char *num;
 
               /* Create the string to be displayed in the window and
                  determine the height and width of the window. */
-              /*              num = xsprintf (" %d ", cur->number); */
-              num = frame_selector (cur->number);
-              width = defaults.bar_x_padding * 2 + rp_text_width (screen, num, 
-1);
-              height = (FONT_HEIGHT (screen) + defaults.bar_y_padding * 2);
+              /*              num = xsprintf (" %d ", cur_frame->number); */
+              num = frame_selector (cur_frame->number);
+              width = defaults.bar_x_padding * 2 + rp_text_width (cur_screen, 
num, -1);
+              height = (FONT_HEIGHT (cur_screen) + defaults.bar_y_padding * 2);
 
               /* Create and map the window. */
-              wins[i] = XCreateWindow (dpy, screen->root, screen->left + 
cur->x, screen->top + cur->y, width, height, 1,
+              wins[i] = XCreateWindow (dpy, cur_screen->root, cur_screen->left 
+ cur_frame->x, cur_screen->top + cur_frame->y, width, height, 1,
                                        CopyFromParent, CopyFromParent, 
CopyFromParent,
                                        CWOverrideRedirect | CWBorderPixel | 
CWBackPixel,
                                        &attr);
@@ -1837,9 +1840,9 @@ read_frame (struct sbuf *s,  struct cmdarg **arg)
               XClearWindow (dpy, wins[i]);
 
               /* Display the frame's number inside the window. */
-             rp_draw_string (screen, wins[i], STYLE_NORMAL,
+             rp_draw_string (cur_screen, wins[i], STYLE_NORMAL,
                              defaults.bar_x_padding,
-                             defaults.bar_y_padding + FONT_ASCENT(screen),
+                             defaults.bar_y_padding + FONT_ASCENT(cur_screen),
                              num, -1);
 
               free (num);
@@ -2684,7 +2687,7 @@ spawn(char *cmd, int raw, rp_frame *frame)
     {
       /* Some process setup to make sure the spawned process runs
          in its own session. */
-      putenv(current_screen()->display_string);
+      putenv(rp_current_screen->display_string);
 #ifdef HAVE_SETSID
       if (setsid() == -1)
 #endif
@@ -2725,7 +2728,7 @@ spawn(char *cmd, int raw, rp_frame *frame)
   child->terminated = 0;
   child->frame = frame;
   child->group = rp_current_group;
-  child->screen = current_screen();
+  child->screen = rp_current_screen;
   child->window_mapped = 0;
 
   list_add (&child->node, &rp_children);
@@ -2833,7 +2836,7 @@ cmd_windows (int interactive, struct cmdarg **args)
 
   if (interactive)
     {
-      s = current_screen ();
+      s = rp_current_screen;
       /* This is a yukky hack. If the bar already hidden then show the
          bar. This handles the case when msgwait is 0 (the bar sticks)
          and the user uses this command to toggle the bar on and
@@ -2961,7 +2964,7 @@ cmd_v_split (int interactive UNUSED, struct cmdarg **args)
   rp_frame *frame;
   int pixels;
 
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
   frame = current_frame();
 
   /* Default to dividing the frame in half. */
@@ -2989,7 +2992,7 @@ cmd_h_split (int interactive UNUSED, struct cmdarg **args)
   rp_frame *frame;
   int pixels;
 
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
   frame = current_frame();
 
   /* Default to dividing the frame in half. */
@@ -3013,7 +3016,7 @@ cmd_h_split (int interactive UNUSED, struct cmdarg **args)
 cmdret *
 cmd_only (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
   remove_all_splits();
   maximize (current_window());
 
@@ -3023,10 +3026,10 @@ cmd_only (int interactive UNUSED, struct cmdarg **args 
UNUSED)
 cmdret *
 cmd_remove (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
   rp_frame *frame;
 
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
 
   if (num_frames(s) <= 1)
     {
@@ -3048,7 +3051,7 @@ cmd_remove (int interactive UNUSED, struct cmdarg **args 
UNUSED)
 cmdret *
 cmd_shrink (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
   resize_shrink_to_window (current_frame());
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -3090,7 +3093,7 @@ static resize_binding resize_bindings[] =
 cmdret *
 cmd_resize (int interactive, struct cmdarg **args)
 {
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
 
   /* If the user calls resize with arguments, treat it like the
      non-interactive version. */
@@ -3198,7 +3201,7 @@ cmd_banish (int interactive UNUSED, struct cmdarg **args 
UNUSED)
 {
   rp_screen *s;
 
-  s = current_screen ();
+  s = rp_current_screen;
 
   XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, s->left + s->width - 2, s->top 
+ s->height - 2);
   return cmdret_new (RET_SUCCESS, NULL);
@@ -3207,7 +3210,7 @@ cmd_banish (int interactive UNUSED, struct cmdarg **args 
UNUSED)
 cmdret *
 cmd_banishrel (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
   rp_window *w = current_window();
   rp_frame *f = current_frame();
 
@@ -3227,7 +3230,7 @@ cmd_ratinfo (int interactive UNUSED, struct cmdarg **args 
UNUSED)
   int mouse_x, mouse_y, root_x, root_y;
   unsigned int mask;
 
-  s = current_screen();
+  s = rp_current_screen;
   XQueryPointer (dpy, s->root, &root_win, &child_win, &mouse_x, &mouse_y, 
&root_x, &root_y, &mask);
 
   return cmdret_new (RET_SUCCESS, "%d %d", mouse_x, mouse_y);
@@ -3243,7 +3246,7 @@ cmd_ratrelinfo (int interactive UNUSED, struct cmdarg 
**args UNUSED)
   int mouse_x, mouse_y, root_x, root_y;
   unsigned int mask;
 
-  s = current_screen();
+  s = rp_current_screen;
   rpw = current_window();
   f = current_frame();
 
@@ -3264,7 +3267,7 @@ cmd_ratwarp (int interactive UNUSED, struct cmdarg **args)
 {
   rp_screen *s;
 
-  s = current_screen ();
+  s = rp_current_screen;
   XWarpPointer (dpy, None, s->root, 0, 0, 0, 0, ARG(0,number), ARG(1,number));
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -3340,7 +3343,7 @@ cmd_curframe (int interactive, struct cmdarg **args 
UNUSED)
 cmdret *
 cmd_license (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
   int x = 10;
   int y = 10;
   int i;
@@ -3416,7 +3419,7 @@ cmd_license (int interactive UNUSED, struct cmdarg **args 
UNUSED)
     }
 
   /* The help window overlaps the bar, so redraw it. */
-  if (current_screen()->bar_is_raised)
+  if (rp_current_screen->bar_is_raised)
     redraw_last_message();
 
   return cmdret_new (RET_SUCCESS, NULL);
@@ -3434,7 +3437,7 @@ cmd_help (int interactive, struct cmdarg **args)
 
   if (interactive)
     {
-      rp_screen *s = current_screen();
+      rp_screen *s = rp_current_screen;
       int i, old_i;
       int x = 10;
       int y = 0;
@@ -3551,7 +3554,7 @@ cmd_help (int interactive, struct cmdarg **args)
        }
 
       /* The help window overlaps the bar, so redraw it. */
-      if (current_screen()->bar_is_raised)
+      if (rp_current_screen->bar_is_raised)
         redraw_last_message();
 
       return cmdret_new (RET_SUCCESS, NULL);
@@ -3745,8 +3748,8 @@ update_gc (rp_screen *s)
 {
   XGCValues gcv;
 
-  gcv.foreground = s->fg_color;
-  gcv.background = s->bg_color;
+  gcv.foreground = rp_glob_screen.fg_color;
+  gcv.background = rp_glob_screen.bg_color;
   gcv.function = GXcopy;
   gcv.line_width = 1;
   gcv.subwindow_mode = IncludeInferiors;
@@ -3755,8 +3758,8 @@ update_gc (rp_screen *s)
                            GCForeground | GCBackground
                            | GCFunction | GCLineWidth
                            | GCSubwindowMode, &gcv);
-  gcv.foreground = s->bg_color;
-  gcv.background = s->fg_color;
+  gcv.foreground = rp_glob_screen.bg_color;
+  gcv.background = rp_glob_screen.fg_color;
   XFreeGC (dpy, s->inverse_gc);
   s->inverse_gc = XCreateGC(dpy, s->root,
                             GCForeground | GCBackground
@@ -3769,10 +3772,11 @@ static void
 update_all_gcs (void)
 {
   int i;
+  rp_screen *cur;
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      update_gc (&screens[i]);
+      update_gc (cur);
     }
 }
 #endif
@@ -3827,7 +3831,7 @@ set_font (struct cmdarg **args)
 {
 #ifdef USE_XFT_FONT
   XftFont *font;
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%s", defaults.font_string);
@@ -3885,7 +3889,7 @@ set_padding (struct cmdarg **args)
 
   /* Resize the frames to make sure they are not too big and not too
      small. */
-  list_for_each_entry (frame,&(current_screen()->frames),node)
+  list_for_each_entry (frame,&(rp_current_screen->frames),node)
     {
       int bk_pos, bk_len;
 
@@ -3899,8 +3903,8 @@ set_padding (struct cmdarg **args)
           frame->width += bk_pos - l;
         }
 
-      if ((bk_pos + bk_len) == (current_screen()->left + 
current_screen()->width - defaults.padding_right))
-        frame->width = current_screen()->left + current_screen()->width - r - 
frame->x;
+      if ((bk_pos + bk_len) == (rp_current_screen->left + 
rp_current_screen->width - defaults.padding_right))
+        frame->width = rp_current_screen->left + rp_current_screen->width - r 
- frame->x;
 
       /* Resize vertically. */
       bk_pos = frame->y;
@@ -3912,8 +3916,8 @@ set_padding (struct cmdarg **args)
           frame->height += bk_pos - t;
         }
 
-      if ((bk_pos + bk_len) == (current_screen()->top + 
current_screen()->height - defaults.padding_bottom))
-        frame->height = current_screen()->top + current_screen()->height - b - 
frame->y;
+      if ((bk_pos + bk_len) == (rp_current_screen->top + 
rp_current_screen->height - defaults.padding_bottom))
+        frame->height = rp_current_screen->top + rp_current_screen->height - b 
- frame->y;
 
       maximize_all_windows_in_frame (frame);
     }
@@ -3952,7 +3956,7 @@ set_border (struct cmdarg **args)
 static cmdret *
 set_barborder (struct cmdarg **args)
 {
-  int i;
+  rp_screen *cur;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%d", defaults.bar_border_width);
@@ -3963,11 +3967,11 @@ set_barborder (struct cmdarg **args)
   defaults.bar_border_width = ARG(0,number);
 
   /* Update the frame and bar windows. */
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      XSetWindowBorderWidth (dpy, screens[i].bar_window, 
defaults.bar_border_width);
-      XSetWindowBorderWidth (dpy, screens[i].frame_window, 
defaults.bar_border_width);
-      XSetWindowBorderWidth (dpy, screens[i].input_window, 
defaults.bar_border_width);
+      XSetWindowBorderWidth (dpy, cur->bar_window, defaults.bar_border_width);
+      XSetWindowBorderWidth (dpy, cur->frame_window, 
defaults.bar_border_width);
+      XSetWindowBorderWidth (dpy, cur->input_window, 
defaults.bar_border_width);
     }
 
   return cmdret_new (RET_SUCCESS, NULL);
@@ -4108,28 +4112,28 @@ set_framefmt (struct cmdarg **args)
 static cmdret *
 set_fgcolor (struct cmdarg **args)
 {
-  int i;
   XColor color, junk;
+  rp_screen *cur;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%s", defaults.fgcolor_string);
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, 
&junk))
+      if (!XAllocNamedColor (dpy, cur->def_cmap, ARG_STRING(0), &color, &junk))
         return cmdret_new (RET_FAILURE, "set fgcolor: unknown color");
 
-      screens[i].fg_color = color.pixel;
-      update_gc (&screens[i]);
-      XSetWindowBorder (dpy, screens[i].bar_window, color.pixel);
-      XSetWindowBorder (dpy, screens[i].input_window, color.pixel);
-      XSetWindowBorder (dpy, screens[i].frame_window, color.pixel);
-      XSetWindowBorder (dpy, screens[i].help_window, color.pixel);
+      rp_glob_screen.fg_color = color.pixel;
+      update_gc (cur);
+      XSetWindowBorder (dpy, cur->bar_window, color.pixel);
+      XSetWindowBorder (dpy, cur->input_window, color.pixel);
+      XSetWindowBorder (dpy, cur->frame_window, color.pixel);
+      XSetWindowBorder (dpy, cur->help_window, color.pixel);
 
 #ifdef USE_XFT_FONT
-      if (!XftColorAllocName (dpy, DefaultVisual (dpy, screens[i].screen_num),
-                              DefaultColormap (dpy, screens[i].screen_num),
-                              ARG_STRING(0), &screens[i].xft_fg_color))
+      if (!XftColorAllocName (dpy, DefaultVisual (dpy, cur->screen_num),
+                              DefaultColormap (dpy, cur->screen_num),
+                              ARG_STRING(0), &cur->xft_fg_color))
         return cmdret_new (RET_FAILURE, "set fgcolor: unknown color");
 #endif
 
@@ -4143,28 +4147,29 @@ set_fgcolor (struct cmdarg **args)
 static cmdret *
 set_bgcolor (struct cmdarg **args)
 {
-  int i;
   XColor color, junk;
+  rp_screen *cur;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%s", defaults.bgcolor_string);
 
-  for (i=0; i<num_screens; i++)
+
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, 
&junk))
+      if (!XAllocNamedColor (dpy, cur->def_cmap, ARG_STRING(0), &color, &junk))
         return cmdret_new (RET_FAILURE, "set bgcolor: unknown color");
 
-      screens[i].bg_color = color.pixel;
-      update_gc (&screens[i]);
-      XSetWindowBackground (dpy, screens[i].bar_window, color.pixel);
-      XSetWindowBackground (dpy, screens[i].input_window, color.pixel);
-      XSetWindowBackground (dpy, screens[i].frame_window, color.pixel);
-      XSetWindowBackground (dpy, screens[i].help_window, color.pixel);
+      rp_glob_screen.bg_color = color.pixel;
+      update_gc (cur);
+      XSetWindowBackground (dpy, cur->bar_window, color.pixel);
+      XSetWindowBackground (dpy, cur->input_window, color.pixel);
+      XSetWindowBackground (dpy, cur->frame_window, color.pixel);
+      XSetWindowBackground (dpy, cur->help_window, color.pixel);
 
 #ifdef USE_XFT_FONT
-      if (!XftColorAllocName (dpy, DefaultVisual (dpy, screens[i].screen_num),
-                              DefaultColormap (dpy, screens[i].screen_num),
-                              ARG_STRING(0), &screens[i].xft_bg_color))
+      if (!XftColorAllocName (dpy, DefaultVisual (dpy, cur->screen_num),
+                              DefaultColormap (dpy, cur->screen_num),
+                              ARG_STRING(0), &cur->xft_bg_color))
         return cmdret_new (RET_FAILURE, "set fgcolor: unknown color");
 #endif
 
@@ -4178,20 +4183,20 @@ set_bgcolor (struct cmdarg **args)
 static cmdret *
 set_fwcolor (struct cmdarg **args)
 {
-  int i;
   XColor color, junk;
   rp_window *win = current_window();
+  rp_screen *cur;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%s", defaults.fwcolor_string);
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, 
&junk))
+      if (!XAllocNamedColor (dpy, cur->def_cmap, ARG_STRING(0), &color, &junk))
         return cmdret_new (RET_FAILURE, "set fwcolor: unknown color");
 
-      screens[i].fw_color = color.pixel;
-      update_gc (&screens[i]);
+      rp_glob_screen.fw_color = color.pixel;
+      update_gc (cur);
 
       free (defaults.fwcolor_string);
       defaults.fwcolor_string = xstrdup (ARG_STRING(0));
@@ -4199,7 +4204,7 @@ set_fwcolor (struct cmdarg **args)
 
   /* Update current window. */
   if (win != NULL)
-    XSetWindowBorder (dpy, win->w, win->scr->fw_color);
+    XSetWindowBorder (dpy, win->w, rp_glob_screen.fw_color);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -4207,20 +4212,20 @@ set_fwcolor (struct cmdarg **args)
 static cmdret *
 set_bwcolor (struct cmdarg **args)
 {
-  int i;
   XColor color, junk;
-  rp_window *win, *cur = current_window();
+  rp_window *win, *cur_win = current_window();
+  rp_screen *cur_screen;
 
   if (args[0] == NULL)
     return cmdret_new (RET_SUCCESS, "%s", defaults.bwcolor_string);
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
-      if (!XAllocNamedColor (dpy, screens[i].def_cmap, ARG_STRING(0), &color, 
&junk))
+      if (!XAllocNamedColor (dpy, cur_screen->def_cmap, ARG_STRING(0), &color, 
&junk))
         return cmdret_new (RET_FAILURE, "set bwcolor: unknown color");
 
-      screens[i].bw_color = color.pixel;
-      update_gc (&screens[i]);
+      rp_glob_screen.bw_color = color.pixel;
+      update_gc (cur_screen);
 
       free (defaults.bwcolor_string);
       defaults.bwcolor_string = xstrdup (ARG_STRING(0));
@@ -4229,8 +4234,8 @@ set_bwcolor (struct cmdarg **args)
   /* Update all the visible windows. */
   list_for_each_entry (win,&rp_mapped_window,node)
     {
-       if (win != cur)
-         XSetWindowBorder (dpy, win->w, win->scr->bw_color);
+       if (win != cur_win)
+         XSetWindowBorder (dpy, win->w, rp_glob_screen.bw_color);
     }
 
 
@@ -4490,7 +4495,7 @@ cmd_swap (int interactive UNUSED, struct cmdarg **args)
   dest_frame = ARG(0, frame);
   src_frame = args[1] ? ARG (1, frame) : current_frame();
 
-  if (!rp_have_xinerama)
+  if (!rp_have_xrandr)
     {
       s = frames_screen(src_frame);
       if (screen_find_frame_by_frame(s, dest_frame) == NULL)
@@ -4622,17 +4627,18 @@ cmd_unalias (int interactive UNUSED, struct cmdarg 
**args)
 cmdret *
 cmd_nextscreen (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  int new_screen;
+  rp_screen *new_screen;
+  rp_frame *new_frame;
+
+  new_screen = screen_next ();
 
   /* No need to go through the motions when we don't have to. */
-  if (num_screens <= 1)
+  if (screen_count() <= 1 || new_screen == rp_current_screen)
     return cmdret_new (RET_FAILURE, "nextscreen: no other screen");
 
-  new_screen = rp_current_screen + 1;
-  if (new_screen >= num_screens)
-    new_screen = 0;
+  new_frame = screen_get_frame (new_screen, new_screen->current_frame);
 
-  set_active_frame (screen_get_frame (&screens[new_screen], 
screens[new_screen].current_frame), 1);
+  set_active_frame (new_frame, 1);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -4640,17 +4646,18 @@ cmd_nextscreen (int interactive UNUSED, struct cmdarg 
**args UNUSED)
 cmdret *
 cmd_prevscreen (int interactive UNUSED, struct cmdarg **args UNUSED)
 {
-  int new_screen;
+  rp_screen *new_screen;
+  rp_frame *new_frame;
+
+  new_screen = screen_prev ();
 
   /* No need to go through the motions when we don't have to. */
-  if (num_screens <= 1)
+  if (screen_count () <= 1 || new_screen == rp_current_screen)
     return cmdret_new (RET_SUCCESS, "prevscreen: no other screen");
 
-  new_screen = rp_current_screen - 1;
-  if (new_screen < 0)
-    new_screen = num_screens - 1;
+  new_frame = screen_get_frame (new_screen, new_screen->current_frame);
 
-  set_active_frame (screen_get_frame (&screens[new_screen], 
screens[new_screen].current_frame), 1);
+  set_active_frame (new_frame, 1);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -4659,15 +4666,23 @@ cmdret *
 cmd_sselect(int interactive UNUSED, struct cmdarg **args)
 {
   int new_screen;
+  rp_frame *new_frame;
+  rp_screen *screen;
 
   new_screen = ARG(0,number);
   if (new_screen < 0)
     return cmdret_new (RET_FAILURE, "sselect: out of range");
 
-  if (new_screen < num_screens)
-    set_active_frame (screen_get_frame (&screens[new_screen], 
screens[new_screen].current_frame), 1);
+  if (new_screen < screen_count ())
+    {
+      screen = screen_at (new_screen);
+      new_frame = screen_get_frame (screen, screen->current_frame);
+      set_active_frame (new_frame, 1);
+    }
   else
-    return cmdret_new (RET_FAILURE, "sselect: out of range");
+    {
+      return cmdret_new (RET_FAILURE, "sselect: out of range");
+    }
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -4854,20 +4869,21 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
 {
   struct list_head *tmp, *iter;
   rp_window *win = NULL;
+  rp_screen *cur_screen;
   int child;
   int status;
   int pid;
-  int i;
   int (*old_handler)(Display *, XErrorEvent *);
 
-  push_frame_undo (current_screen()); /* fdump to stack */
+  push_frame_undo (rp_current_screen); /* fdump to stack */
 
   /* Release event selection on the root windows, so the new WM can
      have it. */
-  for (i=0; i<num_screens; i++)
+
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
-      XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num), 0);
-      deactivate_screen(&screens[i]);
+      XSelectInput (dpy, RootWindow (dpy, cur_screen->screen_num), 0);
+      deactivate_screen (cur_screen);
     }
 
   /* Ungrab all our keys. */
@@ -4888,6 +4904,7 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
 
   /* Disable our SIGCHLD handler */
   set_sig_handler (SIGCHLD, SIG_DFL);
+
   /* Launch the new WM and wait for it to terminate. */
   pid = spawn (ARG_STRING(0), 0, NULL);
   PRINT_DEBUG (("spawn pid: %d\n", pid));
@@ -4895,8 +4912,10 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
     {
       child = waitpid (pid, &status, 0);
     } while (child != -1 && child != pid);
+
   /* Enable our SIGCHLD handler */
   set_sig_handler (SIGCHLD, chld_handler);
+
   /* Some processes may have quit while our sigchld handler was
      disabled, so check for them. */
   check_child_procs();
@@ -4908,26 +4927,33 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
   old_handler = XSetErrorHandler (tmpwm_error_handler);
   do {
     tmpwm_error_raised = 0;
-    for (i=0; i<num_screens; i++)
-      {
-        XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num),
-                     PropertyChangeMask | ColormapChangeMask
-                     | SubstructureRedirectMask | SubstructureNotifyMask
-                     | StructureNotifyMask);
+
+  list_for_each_entry (cur_screen, &rp_screens, node)
+    {
+        XSelectInput (dpy, RootWindow (dpy, cur_screen->screen_num),
+                      PropertyChangeMask | ColormapChangeMask
+                      | SubstructureRedirectMask | SubstructureNotifyMask
+                      | StructureNotifyMask);
         XSync (dpy, False);
-      }
+    }
+
     if (tmpwm_error_raised)
       sleep(1);
   } while (tmpwm_error_raised);
+
   XSetErrorHandler (old_handler);
 
-  for (i=0; i<num_screens; i++)
-    activate_screen (&screens[i]);
+  list_for_each_entry (cur_screen, &rp_screens, node)
+    {
+      activate_screen (cur_screen);
+    }
 
   /* Sort through all the windows in each group and pick out the ones
      that are unmapped or destroyed. */
-  for (i=0; i<num_screens; i++)
-    sync_wins (&screens[i]);
+  list_for_each_entry (cur_screen, &rp_screens, node)
+    {
+    sync_wins (cur_screen);
+    }
 
   /* At this point, new windows have the top level keys grabbed but
      existing windows don't. So grab them on all windows just to be
@@ -4938,7 +4964,7 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
   if (current_window())
     set_active_window (current_window());
   else
-    set_window_focus (current_screen()->key_window);
+    set_window_focus (rp_current_screen->key_window);
 
   /* And we're back in ratpoison. */
   return cmdret_new (RET_SUCCESS, NULL);
@@ -4988,7 +5014,7 @@ cmd_fdump (int interactively UNUSED, struct cmdarg **args)
   char *dump;
 
   if (args[0] == NULL)
-    screen = current_screen ();
+    screen = rp_current_screen;
   else
     {
       int snum;
@@ -4996,10 +5022,10 @@ cmd_fdump (int interactively UNUSED, struct cmdarg 
**args)
 
       if (snum < 0)
         return cmdret_new (RET_FAILURE, "fdump: invalid negative screen 
number");
-      else if (num_screens <= snum)
+      else if (snum >= screen_count ())
         return cmdret_new (RET_FAILURE, "fdump: unknown screen");
       else
-        screen = &screens[snum];
+        screen = screen_at (snum);
     }
 
   dump = fdump (screen);
@@ -5105,8 +5131,8 @@ frestore (char *data, rp_screen *s)
 cmdret *
 cmd_frestore (int interactively UNUSED, struct cmdarg **args)
 {
-  push_frame_undo (current_screen()); /* fdump to stack */
-  return frestore (ARG_STRING(0), current_screen());
+  push_frame_undo (rp_current_screen); /* fdump to stack */
+  return frestore (ARG_STRING(0), rp_current_screen);
 }
 
 cmdret *
@@ -5212,7 +5238,7 @@ cmd_gnumber (int interactive UNUSED, struct cmdarg **args)
       group_resort_group (g);
 
       /* Update the group list. */
-      update_group_names (current_screen());
+      update_group_names (rp_current_screen);
     }
 
   return cmdret_new (RET_SUCCESS, NULL);
@@ -5226,7 +5252,7 @@ cmd_grename (int interactive UNUSED, struct cmdarg **args)
   group_rename (rp_current_group, ARG_STRING(0));
 
   /* Update the group list. */
-  update_group_names (current_screen());
+  update_group_names (rp_current_screen);
 
   return cmdret_new (RET_SUCCESS, NULL);
 }
@@ -5256,7 +5282,7 @@ cmd_groups (int interactive, struct cmdarg **args UNUSED)
 
   if (interactive)
     {
-      s = current_screen ();
+      s = rp_current_screen;
       /* This is a yukky hack. If the bar already hidden then show the
          bar. This handles the case when msgwait is 0 (the bar sticks)
          and the user uses this command to toggle the bar on and
@@ -5571,28 +5597,29 @@ cmd_sfdump (int interactively UNUSED, struct cmdarg 
**args UNUSED)
   char screen_suffix[16];
   cmdret *ret;
   struct sbuf *dump;
-  rp_frame *cur;
-  int i;
+  rp_frame *cur_frame;
+  rp_screen *cur_screen;
 
   dump = sbuf_new (0);
 
-  for (i = 0; i < num_screens; i++)
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
       snprintf (screen_suffix, sizeof (screen_suffix), " %d,",
-                rp_have_xinerama ?
-                  screens[i].xine_screen_num :
-                  screens[i].screen_num);
+                rp_have_xrandr ?
+                cur_screen->xrandr.output :
+                cur_screen->screen_num);
 
-      list_for_each_entry (cur, &(screens[i].frames), node)
+      list_for_each_entry (cur_frame, &(cur_screen->frames), node)
         {
           char *frameset;
 
-         frameset = frame_dump (cur, &screens[i]);
+          frameset = frame_dump (cur_frame, cur_screen);
           sbuf_concat (dump, frameset);
           sbuf_concat (dump, screen_suffix);
           free (frameset);
         }
     }
+
   sbuf_chop (dump);
   ret = cmdret_new (RET_SUCCESS, "%s", sbuf_get (dump));
   sbuf_free (dump);
@@ -5602,14 +5629,16 @@ cmd_sfdump (int interactively UNUSED, struct cmdarg 
**args UNUSED)
 cmdret *
 cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
 {
-  struct sbuf *buffer[num_screens];
   char *copy, *ptr, *token;
   long screen;
   int out_of_screen = 0;
   int restored = 0;
+  int s_count = screen_count ();
+  struct sbuf *buffer[s_count];
+  rp_screen *cur_screen;
   int i;
 
-  for (i = 0; i < num_screens; i++)
+  for (i = 0; i < s_count; i++)
     buffer[i] = sbuf_new (0);
 
   copy = xstrdup (ARG_STRING (0));
@@ -5632,7 +5661,7 @@ cmd_sfrestore (int interactively UNUSED, struct cmdarg 
**args)
       screen = string_to_positive_int (ptr);
 
       /* check that specified screen number is valid */
-      if (screen >= 0 && screen < num_screens)
+      if (screen >= 0 && screen < s_count)
         {
           /* clobber screen number here, frestore() doesn't need it */
           *ptr = '\0';
@@ -5650,13 +5679,13 @@ cmd_sfrestore (int interactively UNUSED, struct cmdarg 
**args)
   free (copy);
 
   /* now restore the frames for each screen */
-  for (i = 0; i < num_screens; i++)
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
       cmdret * ret;
-      push_frame_undo (&screens[i]); /* fdump to stack */
+      push_frame_undo (cur_screen); /* fdump to stack */
       /* FIXME: store RET_SUCCESS || RET_FAILURE for each screen and output
          it later */
-      ret = frestore (sbuf_get (buffer[i]), &screens[i]);
+      ret = frestore (sbuf_get (buffer[i]), cur_screen);
       cmdret_free (ret);
       sbuf_free (buffer[i]);
     }
@@ -5675,12 +5704,12 @@ cmd_sdump (int interactive UNUSED, struct cmdarg **args 
UNUSED)
   cmdret *ret;
   struct sbuf *s;
   char *tmp;
-  int i;
+  rp_screen *cur_screen;
 
   s = sbuf_new (0);
-  for (i = 0; i < num_screens; ++i)
+  list_for_each_entry (cur_screen, &rp_screens, node)
   {
-    tmp = screen_dump (&screens[i]);
+    tmp = screen_dump (cur_screen);
     sbuf_concat (s, tmp);
     sbuf_concat (s, ",");
     free (tmp);
diff --git a/src/bar.c b/src/bar.c
index 0f429b8..afe6f9f 100644
--- a/src/bar.c
+++ b/src/bar.c
@@ -292,7 +292,7 @@ count_lines (char* msg, int len)
 static int
 max_line_length (char* msg)
 {
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   size_t i;
   size_t start;
   int ret = 0;
@@ -512,7 +512,7 @@ static void
 get_mark_box (char *msg, size_t mark_start, size_t mark_end,
               int *x, int *y, int *width, int *height)
 {
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   int start, end;
   int mark_end_is_new_line = 0;
   int start_line;
@@ -578,7 +578,7 @@ draw_box (rp_screen *s, int x, int y, int width, int height)
   GC lgc;
   unsigned long mask;
 
-  lgv.foreground = s->fg_color;
+  lgv.foreground = rp_glob_screen.fg_color;
   mask = GCForeground;
   lgc = XCreateGC(dpy, s->root, mask, &lgv);
 
@@ -621,7 +621,7 @@ marked_message (char *msg, int mark_start, int mark_end)
 static void
 marked_message_internal (char *msg, int mark_start, int mark_end)
 {
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   int num_lines;
   int width;
   int height;
diff --git a/src/communications.c b/src/communications.c
index 76f3b98..c484a28 100644
--- a/src/communications.c
+++ b/src/communications.c
@@ -105,7 +105,7 @@ receive_command_result (Window w)
 }
 
 int
-send_command (unsigned char interactive, unsigned char *cmd, int screen_num)
+send_command (unsigned char interactive, unsigned char *cmd)
 {
   Window w, root;
   int done = 0, return_status = RET_FAILURE;
@@ -114,14 +114,7 @@ send_command (unsigned char interactive, unsigned char 
*cmd, int screen_num)
   s = sbuf_new(0);
   sbuf_printf(s, "%c%s", interactive, cmd);
 
-
-  /* If the user specified a specific screen, then send the event to
-     that screen. */
-  if (screen_num >= 0)
-    root = RootWindow (dpy, screen_num);
-  else
-    root = DefaultRootWindow (dpy);
-
+  root = RootWindow (dpy, DefaultScreen (dpy));
   w = XCreateSimpleWindow (dpy, root, 0, 0, 1, 1, 0, 0, 0);
 
   /* Select first to avoid race condition */
diff --git a/src/communications.h b/src/communications.h
index 6cdd33c..ae958fa 100644
--- a/src/communications.h
+++ b/src/communications.h
@@ -22,6 +22,6 @@
 #ifndef _RATPOISON_COMMUNICATIONS_H
 #define _RATPOISON_COMMUNICATIONS_H 1
 
-int send_command (unsigned char interactive, unsigned char *cmd, int 
screen_num);
+int send_command (unsigned char interactive, unsigned char *cmd);
 
 #endif /* ! _RATPOISON_COMMUNICATIONS_H */
diff --git a/src/data.h b/src/data.h
index 85a0324..a8651c6 100644
--- a/src/data.h
+++ b/src/data.h
@@ -35,6 +35,7 @@
 
 typedef struct rp_window rp_window;
 typedef struct rp_screen rp_screen;
+typedef struct rp_global_screen rp_global_screen;
 typedef struct rp_action rp_action;
 typedef struct rp_keymap rp_keymap;
 typedef struct rp_frame rp_frame;
@@ -149,18 +150,29 @@ struct rp_group
   struct list_head node;
 };
 
+struct rp_global_screen
+{
+  unsigned long fg_color, bg_color, fw_color, bw_color; /* The pixel color. */
+};
+
+struct xrandr_info {
+  int output;
+  int crtc;
+  struct sbuf* name;
+};
+
 struct rp_screen
 {
   GC normal_gc, inverse_gc;
   Window root, bar_window, key_window, input_window, frame_window, help_window;
   int bar_is_raised;
   int screen_num;               /* Our screen number as dictated my X */
-  int xine_screen_num;          /* Our screen number for the Xinerama 
extension */
   Colormap def_cmap;
   Cursor rat;
-  unsigned long fg_color, bg_color, fw_color, bw_color; /* The pixel color. */
 
-  /* Here to abstract over the Xinerama vs X screens difference */
+  struct xrandr_info xrandr;
+
+  /* Here to abstract over the Xrandr vs X screens difference */
   int left, top, width, height;
 
   char *display_string;
@@ -176,6 +188,9 @@ struct rp_screen
      when you switch screens the focus doesn't get frobbed. */
   int current_frame;
 
+  /* This structure can exist in a list. */
+  struct list_head node;
+
 #ifdef USE_XFT_FONT
   XftFont *xft_font;
   XftColor xft_fg_color, xft_bg_color;
diff --git a/src/events.c b/src/events.c
index 814e1ef..496752e 100644
--- a/src/events.c
+++ b/src/events.c
@@ -79,18 +79,9 @@ new_window (XCreateWindowEvent *e)
 
   win = find_window (e->window);
 
-  /* In Xinerama mode, all windows have the same root, so check
-   * all Xinerama screens
-   */
-  if (rp_have_xinerama)
-    {
-      /* New windows belong to the current screen */
-      s = &screens[rp_current_screen];
-    }
-  else
-    {
-      s = find_screen (e->parent);
-    }
+  /* New windows belong to the current screen */
+  s = rp_current_screen;
+
   if (is_rp_window_for_screen(e->window, s)) return;
 
   if (s && win == NULL
@@ -137,7 +128,7 @@ unmap_notify (XEvent *ev)
         {
           cleanup_frame (frame);
           if (frame->number == win->scr->current_frame
-              && current_screen() == win->scr)
+              && rp_current_screen == win->scr)
             set_active_frame (frame, 0);
          /* Since we may have switched windows, call the hook. */
          if (frame->win_number != EMPTY)
@@ -234,7 +225,7 @@ destroy_window (XDestroyWindowEvent *ev)
         {
           cleanup_frame (frame);
           if (frame->number == win->scr->current_frame
-              && current_screen() == win->scr)
+              && rp_current_screen == win->scr)
             set_active_frame (frame, 0);
           /* Since we may have switched windows, call the hook. */
           if (frame->win_number != EMPTY)
@@ -442,11 +433,7 @@ key_press (XEvent *ev)
   unsigned int modifier;
   KeySym ks;
 
-  if (rp_have_xinerama)
-    s = current_screen();
-  else
-    s = find_screen (ev->xkey.root);
-
+  s = rp_current_screen;
   if (!s) return;
 
 #ifdef HIDE_MOUSE
@@ -671,7 +658,7 @@ colormap_notify (XEvent *ev)
       win->colormap = attr.colormap;
 
       if (win == current_window()
-         && !current_screen()->bar_is_raised)
+         && !rp_current_screen->bar_is_raised)
         {
           XInstallColormap (dpy, win->colormap);
         }
@@ -715,18 +702,6 @@ mapping_notify (XMappingEvent *ev)
   grab_keys_all_wins();
 }
 
-static void
-configure_notify (XConfigureEvent *ev)
-{
-  rp_screen *s;
-
-  s = find_screen(ev->window);
-  if (s != NULL)
-    /* This is a root window of a screen,
-     * look if its width or height changed: */
-    screen_update(s,ev->width,ev->height);
-}
-
 /* This is called whan an application has requested the
    selection. Copied from rxvt. */
 static void
@@ -797,6 +772,11 @@ selection_clear (void)
 static void
 delegate_event (XEvent *ev)
 {
+
+#ifdef HAVE_LIBXRANDR
+  xrandr_notify (ev);
+#endif
+
   switch (ev->type)
     {
     case ConfigureRequest:
@@ -867,11 +847,6 @@ delegate_event (XEvent *ev)
       selection_clear();
       break;
 
-    case ConfigureNotify:
-      PRINT_DEBUG (("--- Handling ConfigureNotify ---\n"));
-      configure_notify( &ev->xconfigure );
-      break;
-       
     case MapNotify:
     case Expose:
     case MotionNotify:
@@ -894,14 +869,18 @@ handle_signals (void)
   /* An alarm means we need to hide the popup windows. */
   if (alarm_signalled > 0)
     {
-      int i;
+      rp_screen *cur;
 
       PRINT_DEBUG (("Alarm received.\n"));
 
       /* Only hide the bar if it times out. */
       if (defaults.bar_timeout > 0)
-        for (i=0; i<num_screens; i++)
-          hide_bar (&screens[i]);
+        {
+          list_for_each_entry (cur, &rp_screens, node)
+            {
+              hide_bar (cur);
+            }
+        }
 
       hide_frame_indicator();
       alarm_signalled = 0;
@@ -932,17 +911,19 @@ handle_signals (void)
 
   if (rp_exec_newwm)
     {
-      int i;
+      rp_screen *cur;
 
       PRINT_DEBUG (("Switching to %s\n", rp_exec_newwm));
 
-      putenv(current_screen()->display_string);
+      putenv (rp_current_screen->display_string);
       unhide_all_windows();
       XSync(dpy, False);
-      for (i=0; i<num_screens; i++)
-      {
-             deactivate_screen(&screens[i]);
-      }
+
+      list_for_each_entry (cur, &rp_screens, node)
+        {
+          deactivate_screen (cur);
+        }
+
       execlp (rp_exec_newwm, rp_exec_newwm, (char *)NULL);
 
       /* Failed. Clean up. */
@@ -950,10 +931,11 @@ handle_signals (void)
       perror(" failed");
       free (rp_exec_newwm);
       rp_exec_newwm = NULL;
-      for (i=0; i<num_screens; i++)
-      {
-             activate_screen(&screens[i]);
-      }
+
+      list_for_each_entry (cur, &rp_screens, node)
+        {
+          activate_screen (cur);
+        }
     }
 
   if (hup_signalled > 0)
diff --git a/src/format.c b/src/format.c
index 0706f21..caf8781 100644
--- a/src/format.c
+++ b/src/format.c
@@ -41,7 +41,7 @@ RP_FMT(incheight);
 RP_FMT(incwidth);
 RP_FMT(gravity);
 RP_FMT(screen);
-RP_FMT(xinescreen);
+RP_FMT(xrandrscreen);
 RP_FMT(transient);
 RP_FMT(maxsize);
 RP_FMT(pid);
@@ -72,7 +72,7 @@ struct fmt_item fmt_items[] = {
   { 'M', fmt_maxsize },  
   { 'w', fmt_width },
   { 'W', fmt_incwidth },
-  { 'x', fmt_xinescreen },
+  { 'x', fmt_xrandrscreen},
   { 0, NULL }
 };
 
@@ -218,7 +218,7 @@ fmt_status (rp_window_elem *win_elem, struct sbuf *buf)
 {
   rp_window *other_window;
 
-  other_window = find_window_other (current_screen());
+  other_window = find_window_other (rp_current_screen);
   if (win_elem->win == other_window)
     sbuf_copy (buf, "+");
   else if (win_elem->win == current_window())
@@ -282,9 +282,9 @@ fmt_screen (rp_window_elem *elem, struct sbuf *buf)
 }
 
 static void
-fmt_xinescreen (rp_window_elem *elem, struct sbuf *buf)
+fmt_xrandrscreen (rp_window_elem *elem, struct sbuf *buf)
 {
-  sbuf_printf_concat (buf, "%d", elem->win->scr->xine_screen_num);
+  sbuf_printf_concat (buf, "%d", elem->win->scr->xrandr.output);
 }
 
 static void
diff --git a/src/globals.c b/src/globals.c
index 1481a5c..23aee95 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -59,11 +59,14 @@ Atom _net_wm_window_type;
 Atom _net_wm_window_type_dialog;
 Atom _net_wm_name;
 
-int rp_current_screen;
-rp_screen *screens;
-int num_screens;
+LIST_HEAD (rp_screens);
+rp_screen *rp_current_screen;
+rp_global_screen rp_glob_screen;
+
 Display *dpy;
 
+int rp_have_xrandr;
+
 rp_group *rp_current_group;
 LIST_HEAD (rp_groups);
 LIST_HEAD (rp_children);
@@ -94,11 +97,17 @@ rp_xselection selection;
 static void
 x_export_selection (void)
 {
+  rp_screen *screen;
+
+  list_first(screen, &rp_screens, node);
+  if (!screen)
+    return;
+
   /* Hang the selections off screen 0's key window. */
-  XSetSelectionOwner(dpy, XA_PRIMARY, screens[0].key_window, CurrentTime);
-  if (XGetSelectionOwner(dpy, XA_PRIMARY) != screens[0].key_window)
+  XSetSelectionOwner (dpy, XA_PRIMARY, screen->key_window, CurrentTime);
+  if (XGetSelectionOwner (dpy, XA_PRIMARY) != screen->key_window)
     PRINT_ERROR(("can't get primary selection"));
-  XChangeProperty(dpy, screens[0].root, XA_CUT_BUFFER0, xa_string, 8,
+  XChangeProperty(dpy, screen->root, XA_CUT_BUFFER0, xa_string, 8,
                   PropModeReplace, (unsigned char*)selection.text, 
selection.len);
 }
 
@@ -162,10 +171,10 @@ get_primary_selection(void)
   struct sbuf *s = sbuf_new(0);
 
   for (nread = 0, bytes_after = 1; bytes_after > 0; nread += ct.nitems) {
-    if ((XGetWindowProperty(dpy, current_screen()->input_window, rp_selection, 
(nread / 4), 4096,
-                            True, AnyPropertyType, &ct.encoding,
-                            &ct.format, &ct.nitems, &bytes_after,
-                            &ct.value) != Success)) {
+    if ((XGetWindowProperty (dpy, rp_current_screen->input_window, 
rp_selection, (nread / 4), 4096,
+                             True, AnyPropertyType, &ct.encoding,
+                             &ct.format, &ct.nitems, &bytes_after,
+                             &ct.value) != Success)) {
       XFree(ct.value);
       sbuf_free(s);
       return NULL;
@@ -185,7 +194,7 @@ get_selection (void)
 {
   Atom property;
   XEvent ev;
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   int loops = 1000;
 
   /* Just insert our text, if we own the selection. */
diff --git a/src/globals.h b/src/globals.h
index 1fb7e0f..f3a70d4 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -79,6 +79,9 @@
 /* The list of groups. */
 extern struct list_head rp_groups;
 
+/* Whether or not we support xrandr */
+int rp_have_xrandr;
+
 extern rp_group *rp_current_group;
 
 /* Each child process is stored in this list. spawn, creates a new
@@ -104,9 +107,10 @@ extern struct list_head rp_mapped_window;
    assigned to them and are not visible/active. */
 extern struct list_head rp_unmapped_window;
 
-extern int rp_current_screen;
-extern rp_screen *screens;
-extern int num_screens;
+/* The list of screens. */
+extern struct list_head rp_screens;
+extern rp_screen *rp_current_screen;
+extern rp_global_screen rp_glob_screen;
 
 extern XEvent rp_current_event;
 
@@ -193,8 +197,7 @@ extern struct rp_hook_db_entry rp_hook_db[];
 void set_rp_window_focus (rp_window *win);
 void set_window_focus (Window window);
 
-extern int rp_have_xinerama;
-extern int xine_screen_count;
+extern int rp_have_xrandr;
 
 extern struct numset *rp_frame_numset;
 
diff --git a/src/group.c b/src/group.c
index 02d2073..10d65fc 100644
--- a/src/group.c
+++ b/src/group.c
@@ -494,7 +494,7 @@ group_last_window (rp_group *g, rp_screen *s)
       if (cur->win->last_access >= last_access
           && cur->win != current_window()
           && !find_windows_frame (cur->win)
-          && (cur->win->scr == s || rp_have_xinerama))
+          && (cur->win->scr == s || rp_have_xrandr))
         {
           most_recent = cur;
           last_access = cur->win->last_access;
@@ -514,7 +514,7 @@ group_next_window (rp_group *g, rp_window *win)
 
   /* If there is no window, then get the last accessed one. */
   if (win == NULL)
-    return group_last_window (g, current_screen());
+    return group_last_window (g, rp_current_screen);
 
   /* If we can't find the window, then it's in a different group, so
      get the last accessed one in this group. */
@@ -528,7 +528,7 @@ group_next_window (rp_group *g, rp_window *win)
        cur != we;
        cur = list_next_entry (cur, &g->mapped_windows, node))
     {
-      if (!find_windows_frame (cur->win) && (cur->win->scr == win->scr || 
rp_have_xinerama))
+      if (!find_windows_frame (cur->win) && (cur->win->scr == win->scr || 
rp_have_xrandr))
         {
           return cur->win;
         }
@@ -544,7 +544,7 @@ group_prev_window (rp_group *g, rp_window *win)
 
   /* If there is no window, then get the last accessed one. */
   if (win == NULL)
-    return group_last_window (g, current_screen());
+    return group_last_window (g, rp_current_screen);
 
   /* If we can't find the window, then it's in a different group, so
      get the last accessed one in this group. */
@@ -558,7 +558,7 @@ group_prev_window (rp_group *g, rp_window *win)
        cur != we;
        cur = list_prev_entry (cur, &g->mapped_windows, node))
     {
-      if (!find_windows_frame (cur->win) && (cur->win->scr == win->scr || 
rp_have_xinerama))
+      if (!find_windows_frame (cur->win) && (cur->win->scr == win->scr || 
rp_have_xrandr))
         {
           return cur->win;
         }
@@ -676,14 +676,14 @@ group_last_window_by_class (rp_group *g, char *class)
   int last_access = 0;
   rp_window_elem *most_recent = NULL;
   rp_window_elem *cur;
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
 
   list_for_each_entry (cur, &g->mapped_windows, node)
     {
       if (cur->win->last_access >= last_access
           && cur->win != current_window()
           && !find_windows_frame (cur->win)
-          && (cur->win->scr == s || rp_have_xinerama)
+          && (cur->win->scr == s || rp_have_xrandr)
           && strcmp(class, cur->win->res_class))
         {
           most_recent = cur;
@@ -704,14 +704,14 @@ group_last_window_by_class_complement (rp_group *g, char 
*class)
   int last_access = 0;
   rp_window_elem *most_recent = NULL;
   rp_window_elem *cur;
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
 
   list_for_each_entry (cur, &g->mapped_windows, node)
     {
       if (cur->win->last_access >= last_access
           && cur->win != current_window()
           && !find_windows_frame (cur->win)
-          && (cur->win->scr == s || rp_have_xinerama)
+          && (cur->win->scr == s || rp_have_xrandr)
           && !strcmp(class, cur->win->res_class))
         {
           most_recent = cur;
diff --git a/src/input.c b/src/input.c
index 51443e8..8566e32 100644
--- a/src/input.c
+++ b/src/input.c
@@ -446,7 +446,7 @@ read_single_key (KeySym *keysym, unsigned int *modifiers, 
char *keysym_name, int
   int nbytes;
 
   XGetInputFocus (dpy, &focus, &revert);
-  set_window_focus (current_screen()->key_window);
+  set_window_focus (rp_current_screen->key_window);
   nbytes = read_key (keysym, modifiers, keysym_name, len);
   set_window_focus (focus);
 
@@ -515,7 +515,7 @@ update_input_window (rp_screen *s, rp_input_line *line)
                   line->length);
 
   gcv.function = GXxor;
-  gcv.foreground = s->fg_color ^ s->bg_color;
+  gcv.foreground = rp_glob_screen.fg_color ^ rp_glob_screen.bg_color;
   lgc = XCreateGC (dpy, s->input_window, GCFunction | GCForeground, &gcv);
 
   /* Draw a cheap-o cursor - MkIII */
@@ -537,12 +537,12 @@ ring_bell (void)
   GC lgc;
   XGCValues gcv;
   XWindowAttributes attr;
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
 
   XGetWindowAttributes (dpy, s->input_window, &attr);
 
   gcv.function = GXxor;
-  gcv.foreground = s->fg_color ^ s->bg_color;
+  gcv.foreground = rp_glob_screen.fg_color ^ rp_glob_screen.bg_color;
   lgc = XCreateGC (dpy, s->input_window, GCFunction | GCForeground, &gcv);
 
   XFillRectangle (dpy, s->input_window, lgc, 0, 0, attr.width, attr.height);
@@ -570,7 +570,7 @@ get_more_input (char *prompt, char *preinput, int 
history_id,
 {
   /* Emacs 21 uses a 513 byte string to store the keysym name. */
   char keysym_buf[513];
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   KeySym ch;
   unsigned int modifier;
   rp_input_line *line;
diff --git a/src/linkedlist.c b/src/linkedlist.c
index adedf8a..99cabc0 100644
--- a/src/linkedlist.c
+++ b/src/linkedlist.c
@@ -196,3 +196,142 @@ list_size (struct list_head *list)
 
   return i;
 }
+
+#define MAX_LIST_LENGTH_BITS 20
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+static struct list_head *
+merge(void *priv,
+      int (*cmp)(void *priv, struct list_head *a,
+                 struct list_head *b),
+      struct list_head *a, struct list_head *b)
+{
+       struct list_head head, *tail = &head;
+
+       while (a && b) {
+               /* if equal, take 'a' -- important for sort stability */
+               if ((*cmp) (priv, a, b) <= 0) {
+                       tail->next = a;
+                       a = a->next;
+               } else {
+                       tail->next = b;
+                       b = b->next;
+               }
+               tail = tail->next;
+       }
+       tail->next = a?:b;
+       return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure.  This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+static void
+merge_and_restore_back_links(void *priv,
+                             int (*cmp)(void *priv, struct list_head *a,
+                                       struct list_head *b),
+                             struct list_head *head,
+                             struct list_head *a, struct list_head *b)
+{
+       struct list_head *tail = head;
+       unsigned int count = 0;
+
+       while (a && b) {
+               /* if equal, take 'a' -- important for sort stability */
+               if ((*cmp) (priv, a, b) <= 0) {
+                       tail->next = a;
+                       a->prev = tail;
+                       a = a->next;
+               } else {
+                       tail->next = b;
+                       b->prev = tail;
+                       b = b->next;
+               }
+               tail = tail->next;
+       }
+       tail->next = a ? : b;
+
+       do {
+               /*
+                * In worst cases this loop may run many iterations.
+                * Continue callbacks to the client even though no
+                * element comparison is needed, so the client's cmp()
+                * routine can invoke cond_resched() periodically.
+                */
+               if (!(++count))
+                       (*cmp) (priv, tail->next, tail->next);
+
+               tail->next->prev = tail;
+               tail = tail->next;
+       } while (tail->next);
+
+       tail->next = head;
+       head->prev = tail;
+}
+
+/**
+ * list_sort - sort a list
+ * @priv: private data, opaque to list_sort(), passed to @cmp
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+void
+list_sort(void *priv, struct list_head *head,
+          int (*cmp)(void *priv, struct list_head *a,
+                     struct list_head *b))
+{
+       struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+                                               -- last slot is a sentinel */
+       int lev;  /* index into part[] */
+       int max_lev = 0;
+       struct list_head *list;
+
+       if (list_empty (head))
+               return;
+
+       memset(part, 0, sizeof(part));
+
+       head->prev->next = NULL;
+       list = head->next;
+
+       while (list) {
+               struct list_head *cur = list;
+               list = list->next;
+               cur->next = NULL;
+
+               for (lev = 0; part[lev]; lev++) {
+                       cur = merge (priv, cmp, part[lev], cur);
+                       part[lev] = NULL;
+               }
+               if (lev > max_lev) {
+                       if (lev >= ARRAY_SIZE(part)-1) {
+                               lev--;
+                       }
+                       max_lev = lev;
+               }
+               part[lev] = cur;
+       }
+
+       for (lev = 0; lev < max_lev; lev++)
+               if (part[lev])
+                       list = merge (priv, cmp, part[lev], list);
+
+       merge_and_restore_back_links (priv, cmp, head, part[max_lev], list);
+}
diff --git a/src/linkedlist.h b/src/linkedlist.h
index 42fee3d..6a3da7c 100644
--- a/src/linkedlist.h
+++ b/src/linkedlist.h
@@ -25,6 +25,8 @@
 #ifndef _RATPOISON_LINKLIST_H
 #define _RATPOISON_LINKLIST_H
 
+#include <string.h>
+
 /*
  * Simple doubly linked list implementation.
  *
@@ -214,3 +216,7 @@ void __list_add(struct list_head *new,
   if (&first->member == (head))                                 \
     first = NULL;                                               \
 }
+
+void list_sort(void *priv, struct list_head *head,
+               int (*cmp)(void *priv, struct list_head *a,
+                          struct list_head *b));
diff --git a/src/main.c b/src/main.c
index 3ca8ee6..3f5eb28 100644
--- a/src/main.c
+++ b/src/main.c
@@ -59,7 +59,6 @@ static struct option ratpoison_longopts[] =
     {"version", no_argument,            0,      'v'},
     {"command", required_argument,      0,      'c'},
     {"display", required_argument,      0,      'd'},
-    {"screen",  required_argument,      0,      's'},
     {"file",            required_argument,      0,      'f'},
     {0,         0,                      0,      0} };
 
@@ -338,7 +337,6 @@ print_help (void)
   printf ("-h, --help            Display this help screen\n");
   printf ("-v, --version         Display the version\n");
   printf ("-d, --display <dpy>   Set the X display to use\n");
-  printf ("-s, --screen <num>    Only use the specified screen\n");
   printf ("-c, --command <cmd>   Send ratpoison a colon-command\n");
   printf ("-i, --interactive     Execute commands in interactive mode\n");
   printf ("-f, --file <file>     Specify an alternative configuration 
file\n\n");
@@ -588,12 +586,10 @@ init_defaults (void)
 int
 main (int argc, char *argv[])
 {
-  int i;
   int c;
   char **cmd = NULL;
   int cmd_count = 0;
-  int screen_arg = 0;
-  int screen_num = 0;
+  rp_screen *cur;
   char *display = NULL;
   unsigned char interactive = 0;
   char *alt_rcfile = NULL;
@@ -639,10 +635,6 @@ main (int argc, char *argv[])
         case 'd':
           display = optarg;
           break;
-        case 's':
-          screen_arg = 1;
-          screen_num = strtol (optarg, NULL, 10);
-          break;
         case 'i':
           interactive = 1;
           break;
@@ -686,13 +678,11 @@ main (int argc, char *argv[])
 
   if (cmd_count > 0)
     {
-      int j, screen, exit_status = EXIT_SUCCESS;
-
-      screen = screen_arg ? screen_num : -1;
+      int j, exit_status = EXIT_SUCCESS;
 
       for (j = 0; j < cmd_count; j++)
         {
-          if (!send_command (interactive, (unsigned char *)cmd[j], screen))
+          if (!send_command (interactive, (unsigned char *)cmd[j]))
            exit_status = EXIT_FAILURE;
           free (cmd[j]);
         }
@@ -736,8 +726,13 @@ main (int argc, char *argv[])
   init_xkb ();
   init_groups ();
   init_window_stuff ();
-  init_xinerama ();
-  init_screens (screen_arg, screen_num);
+
+#ifdef HAVE_LIBXRANDR
+  init_xrandr ();
+  rp_have_xrandr = 1;
+#endif
+
+  init_screens ();
 
   init_frame_lists ();
   update_modifier_map ();
@@ -745,19 +740,11 @@ main (int argc, char *argv[])
   initialize_default_keybindings ();
   history_load ();
 
-  /* Scan for windows */
-  if (screen_arg)
-    {
-      rp_current_screen = screen_num;
-      scanwins (&screens[0]);
-    }
-  else
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      rp_current_screen = 0;
-      for (i=0; i<num_screens; i++)
-        {
-          scanwins (&screens[i]);
-        }
+      if (!rp_current_screen)
+        rp_current_screen = cur;
+      scanwins (cur);
     }
 
   if (read_startup_files (alt_rcfile) == -1)
@@ -769,58 +756,18 @@ main (int argc, char *argv[])
 
   /* If no window has focus, give the key_window focus. */
   if (current_window() == NULL)
-    set_window_focus (current_screen()->key_window);
+    set_window_focus (rp_current_screen->key_window);
 
   listen_for_events ();
 
   return EXIT_SUCCESS;
 }
 
-static void
-free_screen (rp_screen *s)
-{
-  rp_frame *frame;
-  struct list_head *iter, *tmp;
-
-  /* Relinquish our hold on the root window. */
-  XSelectInput(dpy, RootWindow (dpy, s->screen_num), 0);
-
-  list_for_each_safe_entry (frame, iter, tmp, &s->frames, node)
-    {
-      frame_free (s, frame);
-    }
-
-  deactivate_screen(s);
-
-  XDestroyWindow (dpy, s->bar_window);
-  XDestroyWindow (dpy, s->key_window);
-  XDestroyWindow (dpy, s->input_window);
-  XDestroyWindow (dpy, s->frame_window);
-  XDestroyWindow (dpy, s->help_window);
-
-#ifdef USE_XFT_FONT
-  if (s->xft_font)
-    {
-      XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
-                    DefaultColormap (dpy, s->screen_num), &s->xft_fg_color);
-      XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
-                    DefaultColormap (dpy, s->screen_num), &s->xft_bg_color);
-      XftFontClose (dpy, s->xft_font);
-    }
-#endif
-
-  XFreeCursor (dpy, s->rat);
-  XFreeColormap (dpy, s->def_cmap);
-  XFreeGC (dpy, s->normal_gc);
-  XFreeGC (dpy, s->inverse_gc);
-
-  free (s->display_string);
-}
-
 void
 clean_up (void)
 {
-  int i;
+  rp_screen *cur;
+  struct list_head *iter, *tmp;
 
   history_save ();
 
@@ -831,11 +778,14 @@ clean_up (void)
   free_window_stuff ();
   free_groups ();
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_safe_entry (cur, iter, tmp, &rp_screens, node)
     {
-      free_screen (&screens[i]);
+      list_del (&cur->node);
+      screen_free (cur);
+      free (cur);
     }
-  free (screens);
+
+  screen_free_final ();
 
   /* Delete the undo histories */
   while (list_size (&rp_frame_undos) > 0)
@@ -849,8 +799,6 @@ clean_up (void)
   /* Free the global frame numset shared by all screens. */
   numset_free (rp_frame_numset);
 
-  free_xinerama();
-
 #ifndef USE_XFT_FONT
   XFreeFontSet (dpy, defaults.font);
 #endif
diff --git a/src/manage.c b/src/manage.c
index 412fc29..2faab71 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -154,21 +154,6 @@ grab_keys_all_wins (void)
     }
 }
 
-rp_screen*
-current_screen (void)
-{
-  int i;
-
-  for (i=0; i<num_screens; i++)
-    {
-      if (screens[i].xine_screen_num == rp_current_screen)
-        return &screens[i];
-    }
-
-  /* This should never happen. */
-  return &screens[0];
-}
-
 void
 update_normal_hints (rp_window *win)
 {
@@ -479,9 +464,6 @@ scanwins(rp_screen *s)
           || attr.override_redirect == True
           || unmanaged_window (wins[i])) continue;
 
-      /* FIXME - with this code, windows which are entirely off-screen
-       * when RP starts won't ever be managed when Xinerama is enabled.
-       */
       {
         XWindowAttributes root_attr;
 
@@ -489,7 +471,7 @@ scanwins(rp_screen *s)
       PRINT_DEBUG (("attrs: %d %d %d %d %d %d\n", root_attr.x, root_attr.y,
                     s->left, s->top, s->left + s->width, s->top + s->height));}
 
-      if (rp_have_xinerama
+      if (rp_have_xrandr
           && ((attr.x > s->left + s->width)
                || (attr.x < s->left)
                || (attr.y > s->top + s->height)
@@ -901,7 +883,7 @@ hide_window (rp_window *win)
   XSelectInput (dpy, win->w, WIN_EVENTS);
   /* Ensure that the window doesn't have the focused border
      color. This is needed by remove_frame and possibly others. */
-  XSetWindowBorder (dpy, win->w, win->scr->bw_color);
+  XSetWindowBorder (dpy, win->w, rp_glob_screen.bw_color);
   set_state (win, IconicState);
 }
 
diff --git a/src/ratpoison.h b/src/ratpoison.h
index 5ff7c44..c98dd40 100644
--- a/src/ratpoison.h
+++ b/src/ratpoison.h
@@ -78,7 +78,7 @@ extern XGCValues gv;
 #include "history.h"
 #include "completions.h"
 #include "hook.h"
-#include "xinerama.h"
+#include "xrandr.h"
 #include "format.h"
 
 void clean_up (void);
diff --git a/src/screen.c b/src/screen.c
index 0afdee0..d3a4d87 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1,4 +1,5 @@
 /* Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <address@hidden>
+ * Copyright (C) 2016 Mathieu OTHACEHE <address@hidden>
  *
  * This file is part of ratpoison.
  *
@@ -22,7 +23,7 @@
 #include <string.h>
 #include <X11/cursorfont.h>
 
-static void init_screen (rp_screen *s, int screen_num);
+static void init_screen (rp_screen *s);
 
 int
 screen_width (rp_screen *s)
@@ -153,79 +154,119 @@ screen_find_frame_by_frame (rp_screen *s, rp_frame *f)
 rp_screen *
 find_screen (Window w)
 {
-  int i;
+  rp_screen *cur;
 
-  for (i=0; i<num_screens; i++)
-    if (screens[i].root == w) return &screens[i];
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      if (cur->root == w)
+        return cur;
+    }
 
-   return NULL;
- }
+  return NULL;
+}
 
 /* Return 1 if w is a root window of any of the screens. */
 int
 is_a_root_window (unsigned int w)
 {
-  int i;
-  for (i=0; i<num_screens; i++)
-    if (screens[i].root == w) return 1;
+  rp_screen *cur;
+
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      if (cur->root == w)
+        return 1;
+    }
+
+  return 0;
+}
+
+rp_screen *
+screen_at(int index)
+{
+  int i = 0;
+  rp_screen *cur;
+
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      if (index == i)
+        return cur;
+
+      i++;
+    }
+
+  return NULL;
+}
+
+static int
+screen_cmp_left (void *priv, struct list_head *a, struct list_head *b)
+{
+  rp_screen *sc_a = container_of (a, typeof(*sc_a), node);
+  rp_screen *sc_b = container_of (b, typeof(*sc_b), node);
+
+  if (sc_a->left < sc_b->left)
+    return -1;
+  else if (sc_a->left > sc_b->left)
+    return 1;
 
   return 0;
 }
 
 void
-init_screens (int screen_arg, int screen_num)
+screen_sort(void)
 {
-  int i;
+  return list_sort (NULL, &rp_screens, screen_cmp_left);
+}
 
-  /* Get the number of screens */
-  if (rp_have_xinerama)
-      num_screens = xine_screen_count;
-  else
-      num_screens = ScreenCount (dpy);
+static void
+init_global_screen (rp_global_screen *s)
+{
+  int screen_num;
 
-  /* make sure the screen specified is valid. */
-  if (screen_arg)
-    {
-      /* Using just a single Xinerama screen doesn't really make sense. So we
-       * disable Xinerama in this case.
-       */
-      if (rp_have_xinerama)
-        {
-            fprintf (stderr, "Warning: selecting a specific Xinerama screen is 
not implemented.\n");
-            rp_have_xinerama = 0;
-            screen_num = 0;
-            num_screens = ScreenCount(dpy);
-        }
+  screen_num = DefaultScreen (dpy);
+  s->fg_color = BlackPixel (dpy, screen_num);
+  s->bg_color = WhitePixel (dpy, screen_num);
+  s->fw_color = BlackPixel (dpy, screen_num);
+  s->bw_color = BlackPixel (dpy, screen_num);
+}
 
-      if (screen_num < 0 || screen_num >= num_screens)
-        {
-          fprintf (stderr, "%d is an invalid screen for the display\n", 
screen_num);
-          exit (EXIT_FAILURE);
-        }
+void
+init_screens ()
+{
+  int i;
+  int screen_count;
+  int *rr_outputs = NULL;
+  rp_screen *screen;
 
-      /* we're only going to use one screen. */
-      num_screens = 1;
-    }
+  /* Get the number of screens */
+  if (rp_have_xrandr) {
+#ifdef HAVE_LIBXRANDR
+    rr_outputs = xrandr_query_screen (&screen_count);
+#endif
+  } else {
+    screen_count = ScreenCount (dpy);
+  }
 
   /* Create our global frame numset */
   rp_frame_numset = numset_new();
 
-  /* Initialize the screens */
-  screens = xmalloc (sizeof (rp_screen) * num_screens);
-  PRINT_DEBUG (("%d screens.\n", num_screens));
+  init_global_screen (&rp_glob_screen);
 
-  if (screen_arg)
+  for (i = 0; i < screen_count; i++)
     {
-      init_screen (&screens[0], screen_num);
-    }
-  else
-    {
-      for (i=0; i<num_screens; i++)
-        {
-          init_screen (&screens[i], i);
-        }
+      screen = xmalloc (sizeof(*screen));
+      list_add (&screen->node, &rp_screens);
+
+#ifdef HAVE_LIBXRANDR
+      if (rp_have_xrandr)
+        xrandr_fill_screen (rr_outputs[i], screen);
+#endif
+      init_screen (screen);
     }
 
+  screen_sort ();
+
+  if (rr_outputs)
+    free (rr_outputs);
 }
 
 static void
@@ -235,41 +276,30 @@ init_rat_cursor (rp_screen *s)
 }
 
 static void
-init_screen (rp_screen *s, int screen_num)
+init_screen (rp_screen *s)
 {
   XGCValues gcv;
   struct sbuf *buf;
-  int xine_screen_num;
   char *colon;
+  int screen_num;
 
-  /* We use screen_num below to refer to the real X screen number, but
-   * if we're using Xinerama, it will only be the Xinerama logical screen
-   * number.  So we shuffle it away and replace it with the real one now,
-   * to cause confusion.  -- CP
-   */
-  if (rp_have_xinerama)
-    {
-      xine_screen_num = screen_num;
-      screen_num = DefaultScreen(dpy);
-      xinerama_get_screen_info(xine_screen_num,
-                      &s->left, &s->top, &s->width, &s->height);
-    }
-  else
+  screen_num = DefaultScreen (dpy);
+
+  if (!rp_have_xrandr)
     {
-      xine_screen_num = screen_num;
       s->left = 0;
       s->top = 0;
-      s->width = DisplayWidth(dpy, screen_num);
-      s->height = DisplayHeight(dpy, screen_num);
+      s->width = DisplayWidth (dpy, screen_num);
+      s->height = DisplayHeight (dpy, screen_num);
     }
 
   /* Select on some events on the root window, if this fails, then
      there is already a WM running and the X Error handler will catch
      it, terminating ratpoison. */
-  XSelectInput(dpy, RootWindow (dpy, screen_num),
-               PropertyChangeMask | ColormapChangeMask
-              | SubstructureRedirectMask | SubstructureNotifyMask
-              | StructureNotifyMask);
+  XSelectInput (dpy, RootWindow (dpy, screen_num),
+                PropertyChangeMask | ColormapChangeMask
+                | SubstructureRedirectMask | SubstructureNotifyMask
+                | StructureNotifyMask);
   XSync (dpy, False);
 
   /* Set the numset for the frames to our global numset. */
@@ -295,21 +325,15 @@ init_screen (rp_screen *s, int screen_num)
 
   PRINT_DEBUG (("display string: %s\n", s->display_string));
 
-  s->screen_num = screen_num;
-  s->xine_screen_num = xine_screen_num;
   s->root = RootWindow (dpy, screen_num);
+  s->screen_num = screen_num;
   s->def_cmap = DefaultColormap (dpy, screen_num);
 
   init_rat_cursor (s);
 
-  s->fg_color = BlackPixel (dpy, s->screen_num);
-  s->bg_color = WhitePixel (dpy, s->screen_num);
-  s->fw_color = BlackPixel (dpy, s->screen_num);
-  s->bw_color = BlackPixel (dpy, s->screen_num);
-
   /* Setup the GC for drawing the font. */
-  gcv.foreground = s->fg_color;
-  gcv.background = s->bg_color;
+  gcv.foreground = rp_glob_screen.fg_color;
+  gcv.background = rp_glob_screen.bg_color;
   gcv.function = GXcopy;
   gcv.line_width = 1;
   gcv.subwindow_mode = IncludeInferiors;
@@ -317,8 +341,8 @@ init_screen (rp_screen *s, int screen_num)
                            GCForeground | GCBackground | GCFunction
                            | GCLineWidth | GCSubwindowMode,
                            &gcv);
-  gcv.foreground = s->bg_color;
-  gcv.background = s->fg_color;
+  gcv.foreground = rp_glob_screen.bg_color;
+  gcv.background = rp_glob_screen.fg_color;
   s->inverse_gc = XCreateGC(dpy, s->root,
                             GCForeground | GCBackground | GCFunction
                             | GCLineWidth | GCSubwindowMode,
@@ -328,28 +352,28 @@ init_screen (rp_screen *s, int screen_num)
   s->bar_is_raised = 0;
   s->bar_window = XCreateSimpleWindow (dpy, s->root, 0, 0, 1, 1,
                                        defaults.bar_border_width,
-                                       s->fg_color, s->bg_color);
+                                       rp_glob_screen.fg_color, 
rp_glob_screen.bg_color);
 
   /* Setup the window that will receive all keystrokes once the prefix
      key has been pressed. */
   s->key_window = XCreateSimpleWindow (dpy, s->root, 0, 0, 1, 1, 0,
-                                       WhitePixel (dpy, s->screen_num),
-                                       BlackPixel (dpy, s->screen_num));
+                                       WhitePixel (dpy, screen_num),
+                                       BlackPixel (dpy, screen_num));
   XSelectInput (dpy, s->key_window, KeyPressMask | KeyReleaseMask);
 
   /* Create the input window. */
   s->input_window = XCreateSimpleWindow (dpy, s->root, 0, 0, 1, 1,
                                          defaults.bar_border_width,
-                                         s->fg_color, s->bg_color);
+                                         rp_glob_screen.fg_color, 
rp_glob_screen.bg_color);
   XSelectInput (dpy, s->input_window, KeyPressMask | KeyReleaseMask);
 
   /* Create the frame indicator window */
   s->frame_window = XCreateSimpleWindow (dpy, s->root, 1, 1, 1, 1, 
defaults.bar_border_width,
-                                         s->fg_color, s->bg_color);
+                                         rp_glob_screen.fg_color, 
rp_glob_screen.bg_color);
 
   /* Create the help window */
   s->help_window = XCreateSimpleWindow (dpy, s->root, s->left, s->top, 
s->width,
-                                        s->height, 0, s->fg_color, 
s->bg_color);
+                                        s->height, 0, rp_glob_screen.fg_color, 
rp_glob_screen.bg_color);
   XSelectInput (dpy, s->help_window, KeyPressMask);
 
   activate_screen(s);
@@ -391,13 +415,13 @@ activate_screen (rp_screen *s)
 {
   /* Add netwm support. FIXME: I think this is busted. */
   XChangeProperty (dpy, RootWindow (dpy, s->screen_num),
-                  _net_supported, XA_ATOM, 32, PropModeReplace, 
-                  (unsigned char*)&_net_wm_pid, 1);
+                   _net_supported, XA_ATOM, 32, PropModeReplace,
+                   (unsigned char*)&_net_wm_pid, 1);
 
   /* set window manager name */
   XChangeProperty (dpy, RootWindow (dpy, s->screen_num),
-                  _net_wm_name, xa_utf8_string, 8, PropModeReplace,
-                  (unsigned char*)"ratpoison", 9);
+                   _net_wm_name, xa_utf8_string, 8, PropModeReplace,
+                   (unsigned char*)"ratpoison", 9);
   XMapWindow (dpy, s->key_window);
 }
 
@@ -409,9 +433,9 @@ deactivate_screen (rp_screen *s)
 
   /* delete everything so noone sees them while we are not there */
   XDeleteProperty (dpy, RootWindow (dpy, s->screen_num),
-                  _net_supported);
+                   _net_supported);
   XDeleteProperty (dpy, RootWindow (dpy, s->screen_num),
-                  _net_wm_name);
+                   _net_wm_name);
 }
 
 static int
@@ -429,18 +453,15 @@ is_rp_window_for_given_screen (Window w, rp_screen *s)
 int
 is_rp_window_for_screen(Window w, rp_screen *s)
 {
-  int i;
+  rp_screen *cur;
 
-  if (rp_have_xinerama)
-    {
-      for (i=0; i<num_screens; i++)
-        if (is_rp_window_for_given_screen(w, &screens[i])) return 1;
-      return 0;
-    }
-  else
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      return is_rp_window_for_given_screen(w, s);
+      if (is_rp_window_for_given_screen (w, cur))
+        return 1;
     }
+
+  return 0;
 }
 
 char *
@@ -450,14 +471,17 @@ screen_dump (rp_screen *screen)
   struct sbuf *s;
 
   s = sbuf_new (0);
-  sbuf_printf (s, "%d %d %d %d %d %d",
-               (rp_have_xinerama)?screen->xine_screen_num:screen->screen_num,
-               screen->left,
-               screen->top,
-               screen->width,
-               screen->height,
-               (current_screen() == screen)?1:0 /* is current? */
-               );
+  if (rp_have_xrandr)
+    sbuf_printf(s, "%s ", sbuf_get (screen->xrandr.name));
+
+  sbuf_printf_concat (s, "%d %d %d %d %d %d",
+                      (rp_have_xrandr) ? screen->xrandr.output : 
screen->screen_num,
+                      screen->left,
+                      screen->top,
+                      screen->width,
+                      screen->height,
+                      (rp_current_screen == screen)?1:0 /* is current? */
+                      );
 
   /* Extract the string and return it, and don't forget to free s. */
   tmp = sbuf_get (s);
@@ -465,27 +489,67 @@ screen_dump (rp_screen *screen)
   return tmp;
 }
 
+int
+screen_count (void)
+{
+  return list_size (&rp_screens);
+}
+
+rp_screen *
+screen_next (void)
+{
+  return list_next_entry (rp_current_screen, &rp_screens, node);
+}
+
+rp_screen *
+screen_prev (void)
+{
+  return list_prev_entry (rp_current_screen, &rp_screens, node);
+}
+
+static void
+screen_remove_current (rp_screen *s)
+{
+  rp_screen *new_screen;
+  rp_frame *new_frame;
+  rp_window *cur_win;
+  int cur_frame;
+
+  cur_win = current_window ();
+  new_screen = screen_next ();
+
+  cur_frame = new_screen->current_frame;
+  new_frame = screen_get_frame (new_screen, cur_frame);
+
+  set_active_frame (new_frame, 1);
+
+  hide_window (cur_win);
+}
+
 void
-screen_update (rp_screen *s, int width, int height)
+screen_update (rp_screen *s, int left, int top, int width, int height)
 {
   rp_frame *f;
-  int oldwidth,oldheight;
+  int oldwidth, oldheight;
 
   PRINT_DEBUG (("screen_update(%d,%d)\n", width, height));
-  if (rp_have_xinerama)
-    {
-      /* TODO: how to do this with xinerama? */
-      return;
-    }
 
-  if (s->width == width && s->height == height)
+  if (s->width  == width  &&
+      s->height == height &&
+      s->left   == left   &&
+      s->top    == top)
     /* nothing to do */
     return;
 
-  oldwidth = s->width; oldheight = s->height;
-  s->width = width; s->height = height;
+  oldwidth = s->width;
+  oldheight = s->height;
 
-  XResizeWindow (dpy, s->help_window, width, height);
+  s->left = left;
+  s->top = top;
+  s->width = width;
+  s->height = height;
+
+  XMoveResizeWindow (dpy, s->help_window, s->left, s->top, s->width, 
s->height);
 
   list_for_each_entry (f, &s->frames, node)
     {
@@ -496,3 +560,99 @@ screen_update (rp_screen *s, int width, int height)
       maximize_all_windows_in_frame (f);
     }
 }
+
+rp_screen *
+screen_add (int rr_output)
+{
+  rp_screen *screen;
+
+  screen = xmalloc (sizeof(*screen));
+  list_add (&screen->node, &rp_screens);
+
+  if (!rp_current_screen)
+    rp_current_screen = screen;
+
+  change_windows_screen (NULL, screen);
+
+#ifdef HAVE_LIBXRANDR
+  xrandr_fill_screen (rr_output, screen);
+#endif
+  init_screen (screen);
+  init_frame_list (screen);
+
+  return screen;
+}
+
+void
+screen_del (rp_screen *s)
+{
+  /*
+   * The deleted screen cannot be the current screen anymore,
+   * focus the next one.
+   */
+  if (s == rp_current_screen) {
+    screen_remove_current (s);
+  } else {
+    rp_frame *cur_frame;
+    rp_window *cur_win;
+
+    cur_frame = screen_get_frame (s, s->current_frame);
+    cur_win = find_window_number (cur_frame->win_number);
+    hide_window (cur_win);
+  }
+
+  change_windows_screen (s, rp_current_screen);
+  screen_free (s);
+
+  list_del (&s->node);
+  free (s);
+}
+
+void
+screen_free (rp_screen *s)
+{
+  rp_frame *frame;
+  struct list_head *iter, *tmp;
+
+  list_for_each_safe_entry (frame, iter, tmp, &s->frames, node)
+    {
+      frame_free (s, frame);
+    }
+
+  deactivate_screen(s);
+
+  XDestroyWindow (dpy, s->bar_window);
+  XDestroyWindow (dpy, s->key_window);
+  XDestroyWindow (dpy, s->input_window);
+  XDestroyWindow (dpy, s->frame_window);
+  XDestroyWindow (dpy, s->help_window);
+
+#ifdef USE_XFT_FONT
+  if (s->xft_font)
+    {
+      XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
+                    DefaultColormap (dpy, s->screen_num), &s->xft_fg_color);
+      XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
+                    DefaultColormap (dpy, s->screen_num), &s->xft_bg_color);
+      XftFontClose (dpy, s->xft_font);
+    }
+#endif
+
+  XFreeCursor (dpy, s->rat);
+  XFreeColormap (dpy, s->def_cmap);
+  XFreeGC (dpy, s->normal_gc);
+  XFreeGC (dpy, s->inverse_gc);
+
+  free (s->display_string);
+
+  if (rp_have_xrandr)
+    free (s->xrandr.name);
+}
+
+void
+screen_free_final (void)
+{
+  /* Relinquish our hold on the root window. */
+  XSelectInput(dpy, RootWindow (dpy, DefaultScreen (dpy)), 0);
+
+}
diff --git a/src/screen.h b/src/screen.h
index 6bad555..eef6c42 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -35,7 +35,7 @@ void frameset_free (struct list_head *head);
 rp_frame *screen_get_frame (rp_screen *s, int frame_num);
 rp_frame *screen_find_frame_by_frame (rp_screen *s, rp_frame *f);
 
-void init_screens (int screen_arg, int screen_num);
+void init_screens ();
 void activate_screen (rp_screen *s);
 void deactivate_screen (rp_screen *s);
 
@@ -44,5 +44,22 @@ int is_a_root_window (unsigned int w);
 
 char *screen_dump (rp_screen *screen);
 
-void screen_update (rp_screen *s, int width, int height);
+void screen_update (rp_screen *s, int left, int top, int width, int height);
+
+int screen_count (void);
+
+rp_screen *screen_next(void);
+rp_screen *screen_prev(void);
+
+rp_screen *screen_at (int index);
+
+rp_screen *screen_by_output(int rr_output);
+rp_screen *screen_by_crtc(int rr_crtc);
+void screen_sort(void);
+
+rp_screen *screen_add(int rr_output);
+void screen_del(rp_screen *s);
+void screen_free (rp_screen *s);
+void screen_free_final(void);
+
 #endif
diff --git a/src/split.c b/src/split.c
index b36b99e..5f74777 100644
--- a/src/split.c
+++ b/src/split.c
@@ -41,24 +41,10 @@ update_last_access (rp_frame *frame)
 rp_frame *
 current_frame (void)
 {
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
   return screen_get_frame (s, s->current_frame);
 }
 
-int
-num_frames (rp_screen *s)
-{
- int count = 0;
- rp_frame *cur;
-
- list_for_each_entry (cur, &s->frames, node)
-   {
-     count++;
-   }
-
- return count;
-}
-
 void
 cleanup_frame (rp_frame *frame)
 {
@@ -95,7 +81,7 @@ set_frames_window (rp_frame *frame, rp_window *win)
       win->frame_number = frame->number;
 
       /* We need to make sure that win and frame are on the same screen,
-       * since with Xinerama, windows can move from one screen to another.
+       * since with Xrandr, windows can move from one screen to another.
        */
       win->scr = frames_screen(frame);
     }
@@ -110,15 +96,17 @@ set_frames_window (rp_frame *frame, rp_window *win)
 rp_screen *
 frames_screen (rp_frame *frame)
 {
-  int i;
-  rp_frame *cur;
+  rp_frame *cur_frame;
+  rp_screen *cur_screen;
 
-  for (i=0; i<num_screens; i++)
-    list_for_each_entry (cur, &screens[i].frames, node)
-      {
-        if (frame == cur)
-          return &screens[i];
-      }
+  list_for_each_entry (cur_screen, &rp_screens, node)
+    {
+      list_for_each_entry (cur_frame, &cur_screen->frames, node)
+        {
+          if (frame == cur_frame)
+            return cur_screen;
+        }
+    }
 
   /* This SHOULD be impossible to get to. FIXME: It'll crash higher up if we
      return NULL. */
@@ -171,10 +159,12 @@ create_initial_frame (rp_screen *screen)
 void
 init_frame_lists (void)
 {
-  int i;
+  rp_screen *cur;
 
-  for (i=0; i<num_screens; i++)
-    init_frame_list (&screens[i]);
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      init_frame_list (cur);
+    }
 }
 
 void
@@ -188,21 +178,19 @@ init_frame_list (rp_screen *screen)
 rp_frame *
 find_last_frame (void)
 {
-  rp_frame *cur, *last = NULL;
+  rp_frame *cur_frame, *last = NULL;
+  rp_screen *cur_screen;
   int last_access = -1;
-  int i;
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
-      rp_screen *s = &screens[i];
-
-      list_for_each_entry (cur, &s->frames, node)
+      list_for_each_entry (cur_frame, &cur_screen->frames, node)
         {
-          if (cur->number != current_screen()->current_frame
-              && cur->last_access > last_access)
+          if (cur_frame->number != rp_current_screen->current_frame &&
+              cur_frame->last_access > last_access)
             {
-              last_access = cur->last_access;
-              last = cur;
+              last_access = cur_frame->last_access;
+              last = cur_frame;
             }
         }
     }
@@ -227,6 +215,12 @@ find_windows_frame (rp_window *win)
   return NULL;
 }
 
+int
+num_frames (rp_screen *s)
+{
+  return list_size (&s->frames);
+}
+
 rp_frame *
 find_frame_next (rp_frame *frame)
 {
@@ -277,7 +271,7 @@ find_window_for_frame (rp_frame *frame)
 
   list_for_each_entry (cur, &rp_current_group->mapped_windows, node)
     {
-      if ((cur->win->scr == s || rp_have_xinerama)
+      if ((cur->win->scr == s || rp_have_xrandr)
           && cur->win != current_window()
           && !find_windows_frame (cur->win)
           && cur->win->last_access >= last_access
@@ -382,7 +376,7 @@ void
 remove_all_splits (void)
 {
   struct list_head *tmp, *iter;
-  rp_screen *s = current_screen();
+  rp_screen *s = rp_current_screen;
   rp_frame *frame;
   rp_window *win;
 
@@ -822,9 +816,9 @@ remove_frame (rp_frame *frame)
 void
 set_active_frame (rp_frame *frame, int force_indicator)
 {
-  rp_screen *old_s = current_screen();
+  rp_screen *old_s = rp_current_screen;
   rp_screen *s = frames_screen (frame);
-  int old = current_screen()->current_frame;
+  int old = rp_current_screen->current_frame;
   rp_window *win, *old_win;
   rp_frame *old_frame;
 
@@ -845,7 +839,7 @@ set_active_frame (rp_frame *frame, int force_indicator)
   s->current_frame = frame->number;
 
   /* If frame->win == NULL, then rp_current_screen is not updated. */
-  rp_current_screen = s->xine_screen_num;
+  rp_current_screen = s;
 
   update_bar (s);
 
@@ -926,15 +920,18 @@ blank_frame (rp_frame *frame)
 void
 hide_frame_indicator (void)
 {
-  int i;
-  for (i=0; i<num_screens; i++)
-    XUnmapWindow (dpy, screens[i].frame_window);
+  rp_screen *cur;
+
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+    XUnmapWindow (dpy, cur->frame_window);
+    }
 }
 
 void
 show_frame_indicator (int force)
 {
-  if (num_frames (current_screen()) > 1 || force)
+  if (num_frames (rp_current_screen) > 1 || force)
     {
       hide_frame_indicator ();
       show_frame_message (defaults.frame_fmt);
@@ -945,7 +942,7 @@ show_frame_indicator (int force)
 void
 show_frame_message (char *msg)
 {
-  rp_screen *s = current_screen ();
+  rp_screen *s = rp_current_screen;
   int width, height;
   rp_frame *frame;
   rp_window *win;
@@ -1072,17 +1069,15 @@ find_frame_right (rp_frame *frame)
 rp_frame *
 find_frame_number (int num)
 {
-  int i;
-  rp_frame *cur;
+  rp_frame *cur_frame;
+  rp_screen *cur_screen;
 
-  for (i=0; i<num_screens; i++)
+  list_for_each_entry (cur_screen, &rp_screens, node)
     {
-      rp_screen *s = &screens[i];
-
-      list_for_each_entry (cur, &s->frames, node)
+      list_for_each_entry (cur_frame, &cur_screen->frames, node)
         {
-          if (cur->number == num)
-            return cur;
+          if (cur_frame->number == num)
+            return cur_frame;
         }
     }
 
diff --git a/src/split.h b/src/split.h
index 87bb660..f125df6 100644
--- a/src/split.h
+++ b/src/split.h
@@ -22,7 +22,6 @@
 #ifndef SPLIT_H
 #define SPLIT_H
 
-int num_frames (rp_screen *s);
 rp_window *set_frames_window (rp_frame *frame, rp_window *win);
 void cleanup_frame (rp_frame *frame);
 void maximize_all_windows_in_frame (rp_frame *frame);
@@ -35,6 +34,7 @@ void resize_frame_vertically (rp_frame *frame, int diff);
 void remove_frame (rp_frame *frame);
 rp_window *find_window_for_frame (rp_frame *frame);
 rp_frame *find_windows_frame (rp_window *win);
+int num_frames (rp_screen *s);
 rp_frame *find_frame_next (rp_frame *frame);
 rp_frame *find_frame_prev (rp_frame *frame);
 rp_window *current_window (void);
diff --git a/src/window.c b/src/window.c
index 7d31a87..b7609ca 100644
--- a/src/window.c
+++ b/src/window.c
@@ -412,7 +412,7 @@ give_window_focus (rp_window *win, rp_window *last_win)
   if (last_win != NULL && win != last_win)
     {
       save_mouse_position (last_win);
-      XSetWindowBorder (dpy, last_win->w, last_win->scr->bw_color);
+      XSetWindowBorder (dpy, last_win->w, rp_glob_screen.bw_color);
     }
 
   if (win == NULL) return;
@@ -432,10 +432,10 @@ give_window_focus (rp_window *win, rp_window *last_win)
   if (last_win != NULL) XUninstallColormap (dpy, last_win->colormap);
   XInstallColormap (dpy, win->colormap);
 
-  XSetWindowBorder (dpy, win->w, win->scr->fw_color);
+  XSetWindowBorder (dpy, win->w, rp_glob_screen.fw_color);
 
   /* Finally, give the window focus */
-  rp_current_screen = win->scr->xine_screen_num;
+  rp_current_screen = win->scr;
   set_rp_window_focus (win);
 
   XSync (dpy, False);
@@ -456,31 +456,17 @@ static rp_frame *
 find_frame_non_dedicated(rp_screen *current_screen, rp_frame *current_frame)
 {
   rp_frame *cur;
+  rp_screen *screen;
 
-  /* Try the only / current screen... */
-  for (cur = list_next_entry (current_frame, &current_screen->frames, node);
-       cur != current_frame;
-       cur = list_next_entry (cur, &current_screen->frames, node))
-    {
-      if (!cur->dedicated)
-        return cur;
-    }
-
-  /* If we have Xinerama, we can check *all* screens... */
-  if (rp_have_xinerama)
+  list_for_each_entry (screen, &rp_screens, node)
     {
-      int i;
+      if (current_screen == screen)
+        continue;
 
-      for (i = 0; i < num_screens; i++)
+      list_for_each_entry (cur, &screen->frames, node)
         {
-          if (current_screen == &screens[i])
-            continue;
-
-          list_for_each_entry (cur, &screens[i].frames, node)
-            {
-              if (!cur->dedicated)
-                return cur;
-            }
+          if (!cur->dedicated)
+            return cur;
         }
     }
 
@@ -492,36 +478,30 @@ set_active_window_body (rp_window *win, int force)
 {
   rp_window *last_win;
   rp_frame *frame = NULL, *last_frame = NULL;
-  rp_screen *screen;
 
   if (win == NULL)
     return;
 
   PRINT_DEBUG (("intended_frame_number: %d\n", win->intended_frame_number));
 
-  /* With Xinerama, we can move a window over to the current screen; otherwise
-   * we have to switch to the screen that the window belongs to.
-   */
-  screen = rp_have_xinerama ? current_screen () : win->scr;
-
   /* use the intended frame if we can. */
   if (win->intended_frame_number >= 0)
     {
-      frame = screen_get_frame (screen, win->intended_frame_number);
+      frame = screen_get_frame (rp_current_screen, win->intended_frame_number);
       win->intended_frame_number = -1;
       if (frame != current_frame ())
         last_frame = current_frame ();
     }
 
   if (frame == NULL)
-    frame = screen_get_frame (screen, screen->current_frame);
+    frame = screen_get_frame (rp_current_screen, 
rp_current_screen->current_frame);
 
   if (frame->dedicated && !force)
     {
       /* Try to find a non-dedicated frame. */
       rp_frame *non_dedicated;
 
-      non_dedicated = find_frame_non_dedicated (screen, frame);
+      non_dedicated = find_frame_non_dedicated (rp_current_screen, frame);
       if (non_dedicated != NULL)
         {
           last_frame = frame;
@@ -594,7 +574,7 @@ get_window_list (char *fmt, char *delim, struct sbuf 
*buffer,
   if (buffer == NULL) return;
 
   sbuf_clear (buffer);
-  find_window_other (current_screen());
+  find_window_other (rp_current_screen);
 
   /* We only loop through the current group to look for windows. */
   list_for_each_entry (we,&rp_current_group->mapped_windows,node)
@@ -671,3 +651,15 @@ win_get_frame (rp_window *win)
   else
     return NULL;
 }
+
+void
+change_windows_screen (rp_screen *old_screen, rp_screen *new_screen)
+{
+  rp_window *win;
+
+  list_for_each_entry (win, &rp_mapped_window, node)
+    {
+      if (win->scr == old_screen)
+        win->scr = new_screen;
+    }
+}
diff --git a/src/window.h b/src/window.h
index fdd246c..4ec8ec8 100644
--- a/src/window.h
+++ b/src/window.h
@@ -61,5 +61,6 @@ void set_active_window_force (rp_window *win);
 void set_active_window_body (rp_window *win, int force);
 
 struct rp_child_info *get_child_info (Window w);
+void change_windows_screen (rp_screen *s, rp_screen *new_screen);
 
 #endif /* ! _RATPOISON_LIST_H */
diff --git a/src/xinerama.c b/src/xinerama.c
deleted file mode 100644
index a8bceb2..0000000
--- a/src/xinerama.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* functions for grabbing information about Xinerama screens
- * Copyright (C) 2003 Cameron Patrick
- *
- * This file is part of ratpoison.
- *
- * ratpoison is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * ratpoison is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING.  If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- */
-
-#include "ratpoison.h"
-
-#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
-# include <X11/extensions/Xinerama.h>
-# define XINERAMA
-#endif
-
-int rp_have_xinerama = 0;
-int xine_screen_count;
-
-#ifdef XINERAMA
-static XineramaScreenInfo *xine_screens = NULL;
-#endif
-
-void
-init_xinerama(void)
-{
-#ifdef XINERAMA
-        int evbase, errbase, major, minor;
-
-        rp_have_xinerama = 0;
-
-        if (xine_screens) XFree(xine_screens);
-
-        if (!XineramaQueryExtension(dpy, &evbase, &errbase)) {
-                return;
-        }
-
-        if (XineramaQueryVersion(dpy, &major, &minor) == 0) {
-                return;
-        }
-
-        if (major != 1) {
-                fprintf (stderr, "Warning: Xinerama version %d.%d not 
supported\n", major, minor);
-                return;
-        }
-
-        if (!XineramaIsActive(dpy)) {
-                return;
-        }
-
-        xine_screens = XineramaQueryScreens(dpy, &xine_screen_count);
-        if (xine_screens == NULL) {
-                return;
-        }
-        if (xine_screen_count < 2) {
-               XFree (xine_screens);
-               xine_screens = NULL;
-               return;
-        }
-
-        rp_have_xinerama = 1;
-#else
-        rp_have_xinerama = 0;
-#endif
-}
-
-#ifdef XINERAMA
-void xinerama_get_screen_info(int sc, int *x, int *y, int *w, int *h)
-{
-        if ((sc < xine_screen_count) && (sc >= 0)) {
-                *x = xine_screens[sc].x_org;
-                *y = xine_screens[sc].y_org;
-                *w = xine_screens[sc].width;
-                *h = xine_screens[sc].height;
-        }
-}
-#else
-void xinerama_get_screen_info(int sc UNUSED, int *x UNUSED, int *y UNUSED, int 
*w UNUSED, int *h UNUSED)
-{
-}
-#endif
-
-void
-free_xinerama(void)
-{
-#ifdef XINERAMA
-        if (xine_screens) {
-                XFree(xine_screens);
-        }
-        rp_have_xinerama = 0;
-#endif
-}
diff --git a/src/xrandr.c b/src/xrandr.c
new file mode 100644
index 0000000..f2ea804
--- /dev/null
+++ b/src/xrandr.c
@@ -0,0 +1,204 @@
+/* functions for grabbing information about xrandr screens
+ * Copyright (C) 2016 Mathieu OTHACEHE <address@hidden>
+ *
+ * This file is part of ratpoison.
+ *
+ * ratpoison is free software; you can redistribute it and/or moify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * ratpoison is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307 USA
+ */
+
+#include "ratpoison.h"
+
+#include <X11/extensions/Xrandr.h>
+
+static int xrandr_evbase;
+
+#define XRANDR_MAJOR 1
+#define XRANDR_MINOR 2
+
+void
+init_xrandr (void)
+{
+  int errbase, major, minor;
+
+  if (!XRRQueryExtension (dpy, &xrandr_evbase, &errbase)) {
+    return;
+  }
+
+  if (XRRQueryVersion (dpy, &major, &minor) == 0) {
+    return;
+  }
+
+  if (major != XRANDR_MAJOR ||
+      (major == XRANDR_MAJOR && minor < XRANDR_MINOR)) {
+    PRINT_ERROR (("Xrandr version %d.%d is not supported\n", major, minor));
+    return;
+  }
+
+  XRRSelectInput (dpy, RootWindow (dpy, DefaultScreen(dpy)),
+                  RRCrtcChangeNotifyMask | RROutputChangeNotifyMask);
+}
+
+int *
+xrandr_query_screen (int *screen_count)
+{
+  XRRScreenResources *res;
+  XRROutputInfo *outinfo;
+  int *output_array;
+  int count = 0;
+  int i;
+
+  res = XRRGetScreenResources (dpy, RootWindow (dpy, DefaultScreen (dpy)));
+  output_array = xmalloc (res->noutput * sizeof(int));
+
+  for (i = 0; i < res->noutput; i++) {
+    outinfo = XRRGetOutputInfo (dpy, res, res->outputs[i]);
+    if (!outinfo->crtc)
+      continue;
+
+    output_array[count] = res->outputs[i];
+    count++;
+
+    XRRFreeOutputInfo (outinfo);
+  }
+
+  *screen_count = count;
+  XRRFreeScreenResources (res);
+
+  return output_array;
+}
+
+static rp_screen *
+xrandr_screen_output (int rr_output)
+{
+  rp_screen *cur;
+
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      if (cur->xrandr.output == rr_output)
+        return cur;
+    }
+
+  return NULL;
+}
+
+static rp_screen *
+xrandr_screen_crtc (int rr_crtc)
+{
+  rp_screen *cur;
+
+  list_for_each_entry (cur, &rp_screens, node)
+    {
+      if (cur->xrandr.crtc == rr_crtc)
+        return cur;
+    }
+
+  return NULL;
+}
+
+void
+xrandr_fill_screen (int rr_output, rp_screen *screen)
+{
+  XRRScreenResources *res;
+  XRROutputInfo *outinfo;
+  XRRCrtcInfo *crtinfo;
+
+  res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen 
(dpy)));
+  outinfo = XRRGetOutputInfo (dpy, res, rr_output);
+  if (!outinfo->crtc)
+    goto free_res;
+
+  crtinfo = XRRGetCrtcInfo (dpy, res, outinfo->crtc);
+  if (!crtinfo)
+    goto free_out;
+
+  screen->xrandr.name = sbuf_new (0);
+  sbuf_concat (screen->xrandr.name, outinfo->name);
+
+  screen->xrandr.output  = rr_output;
+  screen->xrandr.crtc    = outinfo->crtc;
+
+  screen->left   = crtinfo->x;
+  screen->top    = crtinfo->y;
+  screen->width  = crtinfo->width;
+  screen->height = crtinfo->height;
+
+  XRRFreeCrtcInfo (crtinfo);
+ free_out:
+  XRRFreeOutputInfo (outinfo);
+ free_res:
+  XRRFreeScreenResources (res);
+}
+
+static void
+xrandr_output_change (XRROutputChangeNotifyEvent *ev)
+{
+  XRRScreenResources *res;
+  XRROutputInfo *outinfo;
+  rp_screen *screen;
+
+  res = XRRGetScreenResourcesCurrent (dpy, RootWindow (dpy, DefaultScreen 
(dpy)));
+  outinfo = XRRGetOutputInfo (dpy, res, ev->output);
+
+  screen = xrandr_screen_output (ev->output);
+  if (!screen && outinfo->crtc) {
+    screen_add (ev->output);
+    screen_sort ();
+  } else if (screen && !outinfo->crtc) {
+    screen_del (screen);
+  }
+
+  XRRFreeOutputInfo (outinfo);
+  XRRFreeScreenResources (res);
+}
+
+static void
+xrandr_crtc_change (XRRCrtcChangeNotifyEvent *ev)
+{
+  rp_screen *screen;
+
+  if (!ev->crtc || !ev->width || !ev->height)
+    return;
+
+  screen = xrandr_screen_crtc (ev->crtc);
+  if (screen)
+    screen_update (screen, ev->x, ev->y, ev->width, ev->height);
+}
+
+void
+xrandr_notify (XEvent *ev)
+{
+  int ev_code = xrandr_evbase + RRNotify;
+  XRRNotifyEvent *n_event;
+  XRROutputChangeNotifyEvent *o_event;
+  XRRCrtcChangeNotifyEvent *c_event;
+
+  if (ev->type != ev_code)
+    return;
+
+  n_event = (XRRNotifyEvent *)ev;
+  switch (n_event->subtype) {
+  case RRNotify_OutputChange:
+    o_event = (XRROutputChangeNotifyEvent *)ev;
+    xrandr_output_change (o_event);
+    break;
+  case RRNotify_CrtcChange:
+    c_event = (XRRCrtcChangeNotifyEvent *)ev;
+    xrandr_crtc_change (c_event);
+    break;
+  default:
+    break;
+  }
+}
diff --git a/src/xinerama.h b/src/xrandr.h
similarity index 74%
rename from src/xinerama.h
rename to src/xrandr.h
index 233ec46..d765789 100644
--- a/src/xinerama.h
+++ b/src/xrandr.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2003 Cameron Patrick
+/*
+ * Copyright (C) 2016 Mathieu OTHACEHE
  *
  * This file is part of ratpoison.
  *
@@ -18,11 +19,14 @@
  * Boston, MA 02111-1307 USA
  */
 
-#ifndef XINERAMA_H
-#define XINERAMA_H
+#ifndef XRANDR_H
+#define XRANDR_H
 
-void init_xinerama(void);
-void free_xinerama(void);
-void xinerama_get_screen_info(int sc, int *x, int *y, int *w, int *h);
+#include "ratpoison.h"
+
+void init_xrandr(void);
+int *xrandr_query_screen(int *screen_count);
+void xrandr_fill_screen(int rr_output, rp_screen *screen);
+void xrandr_notify(XEvent *ev);
 
 #endif
-- 
2.10.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]