ratpoison-devel
[Top][All Lists]
Advanced

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

[RP] [RFC] Add xrandr support


From: Mathieu OTHACEHE
Subject: [RP] [RFC] Add xrandr support
Date: Thu, 10 Nov 2016 22:16:58 +0100

Drop deprecated xinerama support and replace it with xrandr.

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

Hi all,

It doesn't seem this package is still maintained. It is sad because
ratpoison is a great wm.

Here is a patch to drop deprecated xinerama support and replace it
with xrandr.

Thanks to xrandr, this patch allows :

* Screen hotplug detection
* Screen unplug detection
* Screen resize detection

The list of available screens is not static anymore, and is updated on
xrandr events reception.

I've been using it for the past month and it seems to work well.

Feel free to comment,

Thanks,

Mathieu

 configure.ac                 |  21 ++-
 src/Makefile.am              |   8 +-
 src/actions.c                | 331 +++++++++++++++++++-----------------
 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                |  25 ++-
 src/globals.h                |  13 +-
 src/group.c                  |  18 +-
 src/input.c                  |  10 +-
 src/linkedlist.c             | 136 +++++++++++++++
 src/linkedlist.h             |   6 +
 src/main.c                   |  98 +++--------
 src/manage.c                 |  22 +--
 src/ratpoison.h              |   2 +-
 src/screen.c                 | 389 ++++++++++++++++++++++++++++++-------------
 src/screen.h                 |  24 ++-
 src/split.c                  |  99 +++++------
 src/split.h                  |   6 +-
 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, 1050 insertions(+), 677 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 c53acc0..6103193 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),
+
+  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..1b112e7 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..e0856a1 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..225e64c 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,7 +171,7 @@ 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,
+    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)) {
@@ -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..ec477d6 100644
--- a/src/linkedlist.c
+++ b/src/linkedlist.c
@@ -196,3 +196,139 @@ 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 52dbcce..1f5db82 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} };
 
@@ -353,7 +352,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");
@@ -604,12 +602,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;
@@ -657,10 +653,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;
@@ -704,13 +696,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]);
         }
@@ -754,8 +744,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 ();
@@ -763,19 +758,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)
@@ -787,58 +774,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 ();
 
@@ -849,11 +796,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)
@@ -867,8 +817,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..22bfb20 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,118 @@ 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)
-    {
-      init_screen (&screens[0], screen_num);
-    }
-  else
+  for (i = 0; i < screen_count; i++)
     {
-      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,28 +275,17 @@ 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);
@@ -268,8 +297,8 @@ init_screen (rp_screen *s, int screen_num)
      it, terminating ratpoison. */
   XSelectInput(dpy, RootWindow (dpy, screen_num),
                PropertyChangeMask | ColormapChangeMask
-              | SubstructureRedirectMask | SubstructureNotifyMask
-              | StructureNotifyMask);
+               | SubstructureRedirectMask | SubstructureNotifyMask
+               | StructureNotifyMask);
   XSync (dpy, False);
 
   /* Set the numset for the frames to our global numset. */
@@ -295,21 +324,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 +340,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 +351,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 +414,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 +432,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 +452,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)
+  list_for_each_entry (cur, &rp_screens, node)
     {
-      for (i=0; i<num_screens; i++)
-        if (is_rp_window_for_given_screen(w, &screens[i])) return 1;
-      return 0;
-    }
-  else
-    {
-      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 +470,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 +488,61 @@ screen_dump (rp_screen *screen)
   return tmp;
 }
 
+rp_screen *
+screen_next()
+{
+  return list_next_entry(rp_current_screen, &rp_screens, node);
+}
+
+rp_screen *
+screen_prev()
+{
+  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;
+
+  s->left = left;
+  s->top = top;
+  s->width = width;
+  s->height = height;
 
-  XResizeWindow (dpy, s->help_window, width, height);
+  XMoveResizeWindow (dpy, s->help_window, s->left, s->top, s->width, 
s->height);
 
   list_for_each_entry (f, &s->frames, node)
     {
@@ -496,3 +553,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..820d731 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,25 @@ 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);
+
+rp_screen *screen_next();
+rp_screen *screen_prev();
+
+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);
+
+static inline int screen_count (void)
+{
+  return list_size(&rp_screens);
+}
+
 #endif
diff --git a/src/split.c b/src/split.c
index b36b99e..b80807e 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;
             }
         }
     }
@@ -277,7 +265,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 +370,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 +810,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 +833,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 +914,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 +936,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 +1063,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..ff480a0 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);
@@ -57,4 +56,9 @@ rp_frame * find_frame_number (int num);
 
 rp_frame *current_frame (void);
 
+static inline int num_frames (rp_screen *s)
+{
+  return list_size(&s->frames);
+}
+
 #endif
diff --git a/src/window.c b/src/window.c
index 7d31a87..d439353 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..ef652bc 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..b237839
--- /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]