summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJérémie Courrèges-Anglas <jca@wxcvbn.org>2017-02-15 16:25:34 +0100
committerJérémie Courrèges-Anglas <jca@wxcvbn.org>2017-02-15 16:25:34 +0100
commit2dbe923ea51cc9a13f4c20091e1bfd86f56f9688 (patch)
tree3dd7587776ff1679dac0aee80913244d2dd0cad4
parentc24d1e39ea14666f86c286d72d7f88c9028b3094 (diff)
parent2bda8bc2933dc3be318fbb7d1e290cd6ff4b1262 (diff)
downloadratpoison-2dbe923ea51cc9a13f4c20091e1bfd86f56f9688.zip
Merge branch 'xrandr'
All the hard work on xrandr done by Mathieu OTHACEHE, thanks!
-rw-r--r--configure.ac40
-rw-r--r--doc/ratpoison.texi4
-rw-r--r--src/Makefile.am8
-rw-r--r--src/actions.c377
-rw-r--r--src/bar.c8
-rw-r--r--src/communications.c11
-rw-r--r--src/communications.h2
-rw-r--r--src/data.h34
-rw-r--r--src/events.c81
-rw-r--r--src/format.c10
-rw-r--r--src/frame.c27
-rw-r--r--src/frame.h4
-rw-r--r--src/globals.c31
-rw-r--r--src/globals.h13
-rw-r--r--src/group.c18
-rw-r--r--src/input.c10
-rw-r--r--src/linkedlist.c139
-rw-r--r--src/linkedlist.h6
-rw-r--r--src/main.c95
-rw-r--r--src/manage.c61
-rw-r--r--src/manage.h4
-rw-r--r--src/ratpoison.h3
-rw-r--r--src/screen.c486
-rw-r--r--src/screen.h24
-rw-r--r--src/split.c149
-rw-r--r--src/split.h2
-rw-r--r--src/window.c60
-rw-r--r--src/window.h1
-rw-r--r--src/xinerama.c104
-rw-r--r--src/xrandr.c265
-rw-r--r--src/xrandr.h (renamed from src/xinerama.h)17
31 files changed, 1352 insertions, 742 deletions
diff --git a/configure.ac b/configure.ac
index 504f28f..c685f8e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-AC_INIT([ratpoison], [1.4.9-beta], [ratpoison-devel@nongnu.org])
+AC_INIT([ratpoison], [1.4.9-xrandr4], [ratpoison-devel@nongnu.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_SRCDIR([src/main.c])
@@ -81,7 +81,7 @@ AC_SUBST(XFT_CFLAGS)
AC_SUBST(XFT_LIBS)
AC_ARG_WITH([xkb],
- [AS_HELP_STRING([--disable-xkb], [Don't build XKB support for keyboard input.])],
+ [AS_HELP_STRING([--without-xkb], [Don't build XKB support for keyboard input.])],
[xkb=$withval],
[xkb=yes])
AS_IF([test "X$xkb" = "Xyes"],
@@ -101,6 +101,14 @@ AS_CASE([$enable_mdoc],
AC_MSG_RESULT([$manpage_format])
AC_SUBST([manpage_format])
+AC_MSG_CHECKING([Xrandr support])
+AC_ARG_WITH([xrandr],
+ [AS_HELP_STRING([--without-xrandr],
+ [Build without Xrandr support, default is to use if available])],
+ [with_xrandr=$withval],
+ [with_xrandr=check])
+AC_MSG_RESULT([$with_xrandr])
+
dnl Checks for programs.
AC_PROG_CC
AM_MISSING_PROG([MANDOC], [mandoc])
@@ -158,26 +166,36 @@ 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_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,
[Define to 1 if you have the `XkbKeycodeToKeysym' function.])],
[], [$X_LIBS $X_EXTRA_LIBS])
+mysavedCPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $X_CFLAGS"
+AC_CHECK_HEADERS([X11/extensions/Xrandr.h], [xrandr_h=yes], [xrandr_h=no], [
+#include <X11/Xlib.h>
+])
+CPPFLAGS="$mysavedCPPFLAGS"
+
+AC_CHECK_LIB(Xrandr, XRRGetScreenResources, [libxrandr=yes], [libxrandr=no], [$X_LIBS $X_EXTRA_LIBS])
+
+compile_xrandr=no
+AS_CASE(["$with_xrandr:$xrandr_h:$libxrandr"],
+ [yes:no:*], [AC_MSG_ERROR([*** Can't enable Xrandr support, header Xrandr.h not found.])],
+ [yes:*:no], [AC_MSG_ERROR([*** Can't enable Xrandr support, libXrandr not found.])],
+ [yes:yes:yes|check:yes:yes], [X_LIBS="-lXrandr $X_LIBS"
+ AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you want Xrandr support.])
+ compile_xrandr=yes])
+
+AM_CONDITIONAL(HAVE_XRANDR, [test "$compile_xrandr" = yes])
+
AC_SUBST(X_LIBS)
AC_SUBST(X_EXTRA_LIBS)
AC_SUBST(X_CFLAGS)
diff --git a/doc/ratpoison.texi b/doc/ratpoison.texi
index 6d4a4dd..fb26dac 100644
--- a/doc/ratpoison.texi
+++ b/doc/ratpoison.texi
@@ -906,7 +906,9 @@ window.'' ratpoison means there's no other window to switch to in the
current screen. If you want to switch to the other xterm you can
switch to it by name (use @command{select} or @kbd{C-t '}), by number,
or you can use @command{nextscreen}, @command{prevscreen}, and
-@command{sselect}.
+@command{sselect}. Note, however, that the commands
+@command{focusright}, @command{focusleft}, @command{focusup}, and
+@command{focusdown} do work across screens.
@deffn Command nextscreen
This jumps you to the next X11 screen. @command{nextscreen} is
diff --git a/src/Makefile.am b/src/Makefile.am
index 3ba6de3..bc27439 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_XRANDR
+ratpoison_SOURCES += xrandr.c xrandr.h
+endif
diff --git a/src/actions.c b/src/actions.c
index ef856cf..c2eca3c 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -686,7 +686,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? */
@@ -1247,9 +1247,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
@@ -1485,7 +1485,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);
@@ -1613,7 +1613,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
@@ -1661,7 +1661,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);
}
@@ -1994,45 +1994,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);
@@ -2040,9 +2043,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);
@@ -2887,7 +2890,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
@@ -2928,7 +2931,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);
@@ -3036,7 +3039,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
@@ -3164,7 +3167,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. */
@@ -3192,7 +3195,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. */
@@ -3216,7 +3219,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());
@@ -3226,10 +3229,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)
{
@@ -3251,7 +3254,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);
}
@@ -3293,7 +3296,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. */
@@ -3401,7 +3404,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);
@@ -3410,7 +3413,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();
@@ -3430,7 +3433,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);
@@ -3446,7 +3449,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();
@@ -3467,7 +3470,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);
}
@@ -3543,7 +3546,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;
@@ -3619,7 +3622,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);
@@ -3637,7 +3640,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;
@@ -3754,7 +3757,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);
@@ -3955,8 +3958,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;
@@ -3965,8 +3968,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
@@ -3979,10 +3982,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
@@ -4037,7 +4041,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);
@@ -4095,7 +4099,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;
@@ -4109,8 +4113,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;
@@ -4122,8 +4126,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);
}
@@ -4162,7 +4166,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);
@@ -4173,11 +4177,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);
@@ -4318,28 +4322,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
@@ -4353,28 +4357,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
@@ -4388,20 +4393,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));
@@ -4409,7 +4414,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);
}
@@ -4417,20 +4422,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));
@@ -4439,8 +4444,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);
}
@@ -4700,7 +4705,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)
@@ -4846,17 +4851,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);
}
@@ -4864,17 +4870,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);
}
@@ -4883,15 +4890,19 @@ 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);
- else
- return cmdret_new (RET_FAILURE, "sselect: out of range");
+ screen = screen_number (new_screen);
+ if (!screen)
+ return cmdret_new (RET_FAILURE, "sselect: screen %d not found", new_screen);
+
+ new_frame = screen_get_frame (screen, screen->current_frame);
+ set_active_frame (new_frame, 1);
return cmdret_new (RET_SUCCESS, NULL);
}
@@ -5092,20 +5103,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. */
@@ -5126,6 +5138,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));
@@ -5133,8 +5146,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();
@@ -5146,26 +5161,33 @@ cmd_tmpwm (int interactive UNUSED, struct cmdarg **args)
old_handler = XSetErrorHandler (tmpwm_error_handler);
do {
tmpwm_error_raised = 0;
- for (i=0; i<num_screens; i++)
- {
- XSelectInput(dpy, RootWindow (dpy, screens[i].screen_num),
- PropertyChangeMask | ColormapChangeMask
- | SubstructureRedirectMask | SubstructureNotifyMask
- | StructureNotifyMask);
+
+ list_for_each_entry (cur_screen, &rp_screens, node)
+ {
+ XSelectInput (dpy, RootWindow (dpy, cur_screen->screen_num),
+ PropertyChangeMask | ColormapChangeMask
+ | SubstructureRedirectMask | SubstructureNotifyMask
+ | StructureNotifyMask);
XSync (dpy, False);
- }
+ }
+
if (tmpwm_error_raised)
sleep(1);
} while (tmpwm_error_raised);
+
XSetErrorHandler (old_handler);
- for (i=0; i<num_screens; i++)
- activate_screen (&screens[i]);
+ list_for_each_entry (cur_screen, &rp_screens, node)
+ {
+ activate_screen (cur_screen);
+ }
/* Sort through all the windows in each group and pick out the ones
that are unmapped or destroyed. */
- for (i=0; i<num_screens; i++)
- sync_wins (&screens[i]);
+ list_for_each_entry (cur_screen, &rp_screens, node)
+ {
+ sync_wins (cur_screen);
+ }
/* At this point, new windows have the top level keys grabbed but
existing windows don't. So grab them on all windows just to be
@@ -5176,7 +5198,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);
@@ -5226,7 +5248,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;
@@ -5234,10 +5256,12 @@ 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)
- return cmdret_new (RET_FAILURE, "fdump: unknown screen");
else
- screen = &screens[snum];
+ {
+ screen = screen_number (snum);
+ if (!screen)
+ return cmdret_new (RET_FAILURE, "fdump: screen %d not found", snum);
+ }
}
dump = fdump (screen);
@@ -5343,8 +5367,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 *
@@ -5450,7 +5474,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);
@@ -5464,7 +5488,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);
}
@@ -5494,7 +5518,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
@@ -5809,28 +5833,27 @@ 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);
+ cur_screen->number);
- 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);
@@ -5840,15 +5863,15 @@ 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 i;
+ rp_screen *screen;
+ int out_of_screen = 0, restored = 0;
- for (i = 0; i < num_screens; i++)
- buffer[i] = sbuf_new (0);
+ list_for_each_entry (screen, &rp_screens, node)
+ {
+ sbuf_free (screen->scratch_buffer);
+ screen->scratch_buffer = sbuf_new (0);
+ }
copy = xstrdup (ARG_STRING (0));
@@ -5861,22 +5884,22 @@ cmd_sfrestore (int interactively UNUSED, struct cmdarg **args)
while (token != NULL)
{
+ int snum;
+
/* search for end of frameset */
ptr = token;
while (*ptr != ')')
ptr++;
ptr++;
- screen = string_to_positive_int (ptr);
-
- /* check that specified screen number is valid */
- if (screen >= 0 && screen < num_screens)
+ snum = string_to_positive_int (ptr);
+ screen = screen_number (snum);
+ if (screen)
{
/* clobber screen number here, frestore() doesn't need it */
*ptr = '\0';
- sbuf_concat (buffer[screen], token);
- sbuf_concat (buffer[screen], ",");
- restored++;
+ sbuf_concat (screen->scratch_buffer, token);
+ sbuf_concat (screen->scratch_buffer, ",");
}
else
out_of_screen++;
@@ -5888,22 +5911,30 @@ 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 (screen, &rp_screens, node)
{
- cmdret * ret;
- push_frame_undo (&screens[i]); /* fdump to stack */
- /* FIXME: store RET_SUCCESS || RET_FAILURE for each screen and output
- it later */
- ret = frestore (sbuf_get (buffer[i]), &screens[i]);
+ cmdret *ret;
+
+ if (strlen (sbuf_get (screen->scratch_buffer)) == 0)
+ continue;
+
+ push_frame_undo (screen); /* fdump to stack */
+
+ /* XXX save the failure of each frestore and display it in case of error */
+ ret = frestore (sbuf_get (screen->scratch_buffer), screen);
+ if (ret->success)
+ restored++;
cmdret_free (ret);
- sbuf_free (buffer[i]);
+
+ sbuf_free (screen->scratch_buffer);
+ screen->scratch_buffer = NULL;
}
if (!out_of_screen)
- return cmdret_new (RET_SUCCESS, "Restored %i Frame(s)", restored);
+ return cmdret_new (RET_SUCCESS, "screens restored: %d", restored);
else
return cmdret_new (RET_SUCCESS,
- "Restored %i Frame(s), %i Frame(s) out of Screen(s)",
+ "screens restored: %d, frames out of screen: %d",
restored, out_of_screen);
}
@@ -5913,12 +5944,12 @@ cmd_sdump (int interactive UNUSED, struct cmdarg **args UNUSED)
cmdret *ret;
struct sbuf *s;
char *tmp;
- int i;
+ rp_screen *cur_screen;
s = sbuf_new (0);
- for (i = 0; i < num_screens; ++i)
+ list_for_each_entry (cur_screen, &rp_screens, node)
{
- tmp = screen_dump (&screens[i]);
+ tmp = screen_dump (cur_screen);
sbuf_concat (s, tmp);
sbuf_concat (s, ",");
free (tmp);
diff --git a/src/bar.c b/src/bar.c
index 0f429b8..afe6f9f 100644
--- a/src/bar.c
+++ b/src/bar.c
@@ -292,7 +292,7 @@ count_lines (char* msg, int len)
static int
max_line_length (char* msg)
{
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
size_t i;
size_t start;
int ret = 0;
@@ -512,7 +512,7 @@ static void
get_mark_box (char *msg, size_t mark_start, size_t mark_end,
int *x, int *y, int *width, int *height)
{
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
int start, end;
int mark_end_is_new_line = 0;
int start_line;
@@ -578,7 +578,7 @@ draw_box (rp_screen *s, int x, int y, int width, int height)
GC lgc;
unsigned long mask;
- lgv.foreground = s->fg_color;
+ lgv.foreground = rp_glob_screen.fg_color;
mask = GCForeground;
lgc = XCreateGC(dpy, s->root, mask, &lgv);
@@ -621,7 +621,7 @@ marked_message (char *msg, int mark_start, int mark_end)
static void
marked_message_internal (char *msg, int mark_start, int mark_end)
{
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
int num_lines;
int width;
int height;
diff --git a/src/communications.c b/src/communications.c
index 76f3b98..c484a28 100644
--- a/src/communications.c
+++ b/src/communications.c
@@ -105,7 +105,7 @@ receive_command_result (Window w)
}
int
-send_command (unsigned char interactive, unsigned char *cmd, int screen_num)
+send_command (unsigned char interactive, unsigned char *cmd)
{
Window w, root;
int done = 0, return_status = RET_FAILURE;
@@ -114,14 +114,7 @@ send_command (unsigned char interactive, unsigned char *cmd, int screen_num)
s = sbuf_new(0);
sbuf_printf(s, "%c%s", interactive, cmd);
-
- /* If the user specified a specific screen, then send the event to
- that screen. */
- if (screen_num >= 0)
- root = RootWindow (dpy, screen_num);
- else
- root = DefaultRootWindow (dpy);
-
+ root = RootWindow (dpy, DefaultScreen (dpy));
w = XCreateSimpleWindow (dpy, root, 0, 0, 1, 1, 0, 0, 0);
/* Select first to avoid race condition */
diff --git a/src/communications.h b/src/communications.h
index 6cdd33c..ae958fa 100644
--- a/src/communications.h
+++ b/src/communications.h
@@ -22,6 +22,6 @@
#ifndef _RATPOISON_COMMUNICATIONS_H
#define _RATPOISON_COMMUNICATIONS_H 1
-int send_command (unsigned char interactive, unsigned char *cmd, int screen_num);
+int send_command (unsigned char interactive, unsigned char *cmd);
#endif /* ! _RATPOISON_COMMUNICATIONS_H */
diff --git a/src/data.h b/src/data.h
index 52aaa42..1d3be80 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,37 @@ struct rp_group
struct list_head node;
};
+struct rp_global_screen
+{
+ Window root;
+ unsigned long fg_color, bg_color, fw_color, bw_color; /* The pixel color. */
+
+ /* This numset is responsible for giving out numbers for each screen */
+ struct numset *numset;
+};
+
+struct xrandr_info {
+ int output;
+ int crtc;
+ int primary;
+ 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 */
+ int screen_num; /* Our screen number as dictated by X */
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 */
+ /* Screen number, handled by rp_global_screen numset */
+ int number;
+
+ struct xrandr_info xrandr;
+
+ /* Here to abstract over the Xrandr vs X screens difference */
int left, top, width, height;
char *display_string;
@@ -176,6 +196,12 @@ 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;
+
+ /* Used by sfrestore */
+ struct sbuf *scratch_buffer;
+
#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..e87bce2 100644
--- a/src/events.c
+++ b/src/events.c
@@ -79,19 +79,10 @@ 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);
- }
- if (is_rp_window_for_screen(e->window, s)) return;
+ /* New windows belong to the current screen */
+ s = rp_current_screen;
+
+ if (is_rp_window (e->window)) return;
if (s && win == NULL
&& e->window != s->key_window
@@ -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);
}
@@ -724,10 +711,10 @@ configure_notify (XConfigureEvent *ev)
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);
+ screen_update (s, ev->x, ev->y, ev->width, ev->height);
}
-/* This is called whan an application has requested the
+/* This is called when an application has requested the
selection. Copied from rxvt. */
static void
selection_request (XSelectionRequestEvent *rq)
@@ -797,6 +784,12 @@ selection_clear (void)
static void
delegate_event (XEvent *ev)
{
+
+#ifdef HAVE_XRANDR
+ if (rp_have_xrandr)
+ xrandr_notify (ev);
+#endif
+
switch (ev->type)
{
case ConfigureRequest:
@@ -868,10 +861,13 @@ delegate_event (XEvent *ev)
break;
case ConfigureNotify:
- PRINT_DEBUG (("--- Handling ConfigureNotify ---\n"));
- configure_notify( &ev->xconfigure );
+ if (!rp_have_xrandr)
+ {
+ PRINT_DEBUG (("--- Handling ConfigureNotify ---\n"));
+ configure_notify (&ev->xconfigure);
+ }
break;
-
+
case MapNotify:
case Expose:
case MotionNotify:
@@ -894,14 +890,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 +932,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 +952,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/frame.c b/src/frame.c
index c42e2ab..95e4952 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -47,6 +47,33 @@ frame_bottom (rp_frame *frame)
return frame->y + frame->height;
}
+
+int
+frame_left_abs (rp_frame *frame)
+{
+ rp_screen *s = frames_screen (frame);
+ return s->left + frame->x;
+}
+
+int
+frame_top_abs (rp_frame *frame)
+{
+ rp_screen *s = frames_screen (frame);
+ return s->top + frame->y;
+}
+
+int
+frame_right_abs (rp_frame *frame)
+{
+ return frame_left_abs (frame) + frame->width;
+}
+
+int
+frame_bottom_abs (rp_frame *frame)
+{
+ return frame_top_abs (frame) + frame->height;
+}
+
int
frame_width(rp_frame *frame)
{
diff --git a/src/frame.h b/src/frame.h
index 611ecc0..f78f86c 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -35,6 +35,10 @@ int frame_bottom (rp_frame *frame);
int frame_right (rp_frame *frame);
int frame_top (rp_frame *frame);
int frame_left (rp_frame *frame);
+int frame_bottom_abs (rp_frame *frame);
+int frame_right_abs (rp_frame *frame);
+int frame_top_abs (rp_frame *frame);
+int frame_left_abs (rp_frame *frame);
rp_frame *frame_new (rp_screen *s);
void frame_free (rp_screen *s, rp_frame *f);
diff --git a/src/globals.c b/src/globals.c
index ddb2b89..621dcb6 100644
--- a/src/globals.c
+++ b/src/globals.c
@@ -59,11 +59,14 @@ Atom _net_wm_window_type;
Atom _net_wm_window_type_dialog;
Atom _net_wm_name;
-int rp_current_screen;
-rp_screen *screens;
-int num_screens;
+LIST_HEAD (rp_screens);
+rp_screen *rp_current_screen;
+rp_global_screen rp_glob_screen;
+
Display *dpy;
+int rp_have_xrandr;
+
rp_group *rp_current_group;
LIST_HEAD (rp_groups);
LIST_HEAD (rp_children);
@@ -94,11 +97,17 @@ rp_xselection selection;
static void
x_export_selection (void)
{
+ rp_screen *screen;
+
+ list_first(screen, &rp_screens, node);
+ if (!screen)
+ return;
+
/* Hang the selections off screen 0's key window. */
- XSetSelectionOwner(dpy, XA_PRIMARY, screens[0].key_window, CurrentTime);
- if (XGetSelectionOwner(dpy, XA_PRIMARY) != screens[0].key_window)
+ XSetSelectionOwner (dpy, XA_PRIMARY, screen->key_window, CurrentTime);
+ if (XGetSelectionOwner (dpy, XA_PRIMARY) != screen->key_window)
PRINT_ERROR(("can't get primary selection"));
- XChangeProperty(dpy, screens[0].root, XA_CUT_BUFFER0, xa_string, 8,
+ XChangeProperty(dpy, screen->root, XA_CUT_BUFFER0, xa_string, 8,
PropModeReplace, (unsigned char*)selection.text, selection.len);
}
@@ -162,10 +171,10 @@ get_primary_selection(void)
struct sbuf *s = sbuf_new(0);
for (nread = 0, bytes_after = 1; bytes_after > 0; nread += ct.nitems) {
- if ((XGetWindowProperty(dpy, current_screen()->input_window, rp_selection, (nread / 4), 4096,
- True, AnyPropertyType, &ct.encoding,
- &ct.format, &ct.nitems, &bytes_after,
- &ct.value) != Success)) {
+ if ((XGetWindowProperty (dpy, rp_current_screen->input_window, rp_selection, (nread / 4), 4096,
+ True, AnyPropertyType, &ct.encoding,
+ &ct.format, &ct.nitems, &bytes_after,
+ &ct.value) != Success)) {
XFree(ct.value);
sbuf_free(s);
return NULL;
@@ -185,7 +194,7 @@ get_selection (void)
{
Atom property;
XEvent ev;
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
int loops = 1000;
/* Just insert our text, if we own the selection. */
diff --git a/src/globals.h b/src/globals.h
index 8f0d048..144273d 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 */
+extern 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,9 +197,6 @@ 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 struct numset *rp_frame_numset;
/* Selection handling globals */
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 a81c1af..8abb308 100644
--- a/src/input.c
+++ b/src/input.c
@@ -405,7 +405,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);
@@ -474,7 +474,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 */
@@ -496,12 +496,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);
@@ -529,7 +529,7 @@ get_more_input (char *prompt, char *preinput, int history_id,
{
/* Emacs 21 uses a 513 byte string to store the keysym name. */
char keysym_buf[513];
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
KeySym ch;
unsigned int modifier;
rp_input_line *line;
diff --git a/src/linkedlist.c b/src/linkedlist.c
index adedf8a..99cabc0 100644
--- a/src/linkedlist.c
+++ b/src/linkedlist.c
@@ -196,3 +196,142 @@ list_size (struct list_head *list)
return i;
}
+
+#define MAX_LIST_LENGTH_BITS 20
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
+
+/*
+ * Returns a list organized in an intermediate format suited
+ * to chaining of merge() calls: null-terminated, no reserved or
+ * sentinel head node, "prev" links not maintained.
+ */
+static struct list_head *
+merge(void *priv,
+ int (*cmp)(void *priv, struct list_head *a,
+ struct list_head *b),
+ struct list_head *a, struct list_head *b)
+{
+ struct list_head head, *tail = &head;
+
+ while (a && b) {
+ /* if equal, take 'a' -- important for sort stability */
+ if ((*cmp) (priv, a, b) <= 0) {
+ tail->next = a;
+ a = a->next;
+ } else {
+ tail->next = b;
+ b = b->next;
+ }
+ tail = tail->next;
+ }
+ tail->next = a?:b;
+ return head.next;
+}
+
+/*
+ * Combine final list merge with restoration of standard doubly-linked
+ * list structure. This approach duplicates code from merge(), but
+ * runs faster than the tidier alternatives of either a separate final
+ * prev-link restoration pass, or maintaining the prev links
+ * throughout.
+ */
+static void
+merge_and_restore_back_links(void *priv,
+ int (*cmp)(void *priv, struct list_head *a,
+ struct list_head *b),
+ struct list_head *head,
+ struct list_head *a, struct list_head *b)
+{
+ struct list_head *tail = head;
+ unsigned int count = 0;
+
+ while (a && b) {
+ /* if equal, take 'a' -- important for sort stability */
+ if ((*cmp) (priv, a, b) <= 0) {
+ tail->next = a;
+ a->prev = tail;
+ a = a->next;
+ } else {
+ tail->next = b;
+ b->prev = tail;
+ b = b->next;
+ }
+ tail = tail->next;
+ }
+ tail->next = a ? : b;
+
+ do {
+ /*
+ * In worst cases this loop may run many iterations.
+ * Continue callbacks to the client even though no
+ * element comparison is needed, so the client's cmp()
+ * routine can invoke cond_resched() periodically.
+ */
+ if (!(++count))
+ (*cmp) (priv, tail->next, tail->next);
+
+ tail->next->prev = tail;
+ tail = tail->next;
+ } while (tail->next);
+
+ tail->next = head;
+ head->prev = tail;
+}
+
+/**
+ * list_sort - sort a list
+ * @priv: private data, opaque to list_sort(), passed to @cmp
+ * @head: the list to sort
+ * @cmp: the elements comparison function
+ *
+ * This function implements "merge sort", which has O(nlog(n))
+ * complexity.
+ *
+ * The comparison function @cmp must return a negative value if @a
+ * should sort before @b, and a positive value if @a should sort after
+ * @b. If @a and @b are equivalent, and their original relative
+ * ordering is to be preserved, @cmp must return 0.
+ */
+void
+list_sort(void *priv, struct list_head *head,
+ int (*cmp)(void *priv, struct list_head *a,
+ struct list_head *b))
+{
+ struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists
+ -- last slot is a sentinel */
+ int lev; /* index into part[] */
+ int max_lev = 0;
+ struct list_head *list;
+
+ if (list_empty (head))
+ return;
+
+ memset(part, 0, sizeof(part));
+
+ head->prev->next = NULL;
+ list = head->next;
+
+ while (list) {
+ struct list_head *cur = list;
+ list = list->next;
+ cur->next = NULL;
+
+ for (lev = 0; part[lev]; lev++) {
+ cur = merge (priv, cmp, part[lev], cur);
+ part[lev] = NULL;
+ }
+ if (lev > max_lev) {
+ if (lev >= ARRAY_SIZE(part)-1) {
+ lev--;
+ }
+ max_lev = lev;
+ }
+ part[lev] = cur;
+ }
+
+ for (lev = 0; lev < max_lev; lev++)
+ if (part[lev])
+ list = merge (priv, cmp, part[lev], list);
+
+ merge_and_restore_back_links (priv, cmp, head, part[max_lev], list);
+}
diff --git a/src/linkedlist.h b/src/linkedlist.h
index 42fee3d..6a3da7c 100644
--- a/src/linkedlist.h
+++ b/src/linkedlist.h
@@ -25,6 +25,8 @@
#ifndef _RATPOISON_LINKLIST_H
#define _RATPOISON_LINKLIST_H
+#include <string.h>
+
/*
* Simple doubly linked list implementation.
*
@@ -214,3 +216,7 @@ void __list_add(struct list_head *new,
if (&first->member == (head)) \
first = NULL; \
}
+
+void list_sort(void *priv, struct list_head *head,
+ int (*cmp)(void *priv, struct list_head *a,
+ struct list_head *b));
diff --git a/src/main.c b/src/main.c
index 3c2b300..da6fb9f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -59,7 +59,6 @@ static struct option ratpoison_longopts[] =
{"version", no_argument, 0, 'v'},
{"command", required_argument, 0, 'c'},
{"display", required_argument, 0, 'd'},
- {"screen", required_argument, 0, 's'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0} };
@@ -338,7 +337,6 @@ print_help (void)
printf ("-h, --help Display this help screen\n");
printf ("-v, --version Display the version\n");
printf ("-d, --display <dpy> Set the X display to use\n");
- printf ("-s, --screen <num> Only use the specified screen\n");
printf ("-c, --command <cmd> Send ratpoison a colon-command\n");
printf ("-i, --interactive Execute commands in interactive mode\n");
printf ("-f, --file <file> Specify an alternative configuration file\n\n");
@@ -588,12 +586,9 @@ 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;
char *display = NULL;
unsigned char interactive = 0;
char *alt_rcfile = NULL;
@@ -639,10 +634,6 @@ main (int argc, char *argv[])
case 'd':
display = optarg;
break;
- case 's':
- screen_arg = 1;
- screen_num = strtol (optarg, NULL, 10);
- break;
case 'i':
interactive = 1;
break;
@@ -686,13 +677,11 @@ main (int argc, char *argv[])
if (cmd_count > 0)
{
- int j, screen, exit_status = EXIT_SUCCESS;
-
- screen = screen_arg ? screen_num : -1;
+ int j, exit_status = EXIT_SUCCESS;
for (j = 0; j < cmd_count; j++)
{
- if (!send_command (interactive, (unsigned char *)cmd[j], screen))
+ if (!send_command (interactive, (unsigned char *)cmd[j]))
exit_status = EXIT_FAILURE;
free (cmd[j]);
}
@@ -736,8 +725,12 @@ main (int argc, char *argv[])
init_xkb ();
init_groups ();
init_window_stuff ();
- init_xinerama ();
- init_screens (screen_arg, screen_num);
+
+#ifdef HAVE_XRANDR
+ init_xrandr ();
+#endif
+
+ init_screens ();
init_frame_lists ();
update_modifier_map ();
@@ -745,20 +738,7 @@ 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
- {
- rp_current_screen = 0;
- for (i=0; i<num_screens; i++)
- {
- scanwins (&screens[i]);
- }
- }
+ scanwins ();
if (read_startup_files (alt_rcfile) == -1)
return EXIT_FAILURE;
@@ -769,58 +749,18 @@ main (int argc, char *argv[])
/* If no window has focus, give the key_window focus. */
if (current_window() == NULL)
- set_window_focus (current_screen()->key_window);
+ set_window_focus (rp_current_screen->key_window);
listen_for_events ();
return EXIT_SUCCESS;
}
-static void
-free_screen (rp_screen *s)
-{
- rp_frame *frame;
- struct list_head *iter, *tmp;
-
- /* Relinquish our hold on the root window. */
- XSelectInput(dpy, RootWindow (dpy, s->screen_num), 0);
-
- list_for_each_safe_entry (frame, iter, tmp, &s->frames, node)
- {
- frame_free (s, frame);
- }
-
- deactivate_screen(s);
-
- XDestroyWindow (dpy, s->bar_window);
- XDestroyWindow (dpy, s->key_window);
- XDestroyWindow (dpy, s->input_window);
- XDestroyWindow (dpy, s->frame_window);
- XDestroyWindow (dpy, s->help_window);
-
-#ifdef USE_XFT_FONT
- if (s->xft_font)
- {
- XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
- DefaultColormap (dpy, s->screen_num), &s->xft_fg_color);
- XftColorFree (dpy, DefaultVisual (dpy, s->screen_num),
- DefaultColormap (dpy, s->screen_num), &s->xft_bg_color);
- XftFontClose (dpy, s->xft_font);
- }
-#endif
-
- XFreeCursor (dpy, s->rat);
- XFreeColormap (dpy, s->def_cmap);
- XFreeGC (dpy, s->normal_gc);
- XFreeGC (dpy, s->inverse_gc);
-
- free (s->display_string);
-}
-
void
clean_up (void)
{
- int i;
+ rp_screen *cur;
+ struct list_head *iter, *tmp;
history_save ();
@@ -831,11 +771,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 */
clear_frame_undos ();
@@ -843,8 +786,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 0431cfd..db77035 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -152,21 +152,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)
{
@@ -460,40 +445,34 @@ unmanage (rp_window *w)
/* When starting up scan existing windows and start managing them. */
void
-scanwins(rp_screen *s)
+scanwins (void)
{
rp_window *win;
XWindowAttributes attr;
unsigned int i, nwins;
Window dw1, dw2, *wins;
- XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins);
+ XQueryTree(dpy, rp_glob_screen.root, &dw1, &dw2, &wins, &nwins);
PRINT_DEBUG (("windows: %d\n", nwins));
for (i = 0; i < nwins; i++)
{
+ rp_screen *screen;
+
XGetWindowAttributes(dpy, wins[i], &attr);
- if (is_rp_window_for_screen(wins[i], s)
+ if (is_rp_window (wins[i])
|| 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;
-
- XGetWindowAttributes (dpy, s->root, &root_attr);
- 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
- && ((attr.x > s->left + s->width)
- || (attr.x < s->left)
- || (attr.y > s->top + s->height)
- || (attr.y < s->top))) continue;
+ screen = find_screen_by_attr (attr);
+ if (!screen)
+ {
+ PRINT_ERROR (("Unable to find a screen by window attributes\n"));
+ continue;
+ }
- win = add_to_window_list (s, wins[i]);
+ win = add_to_window_list (screen, wins[i]);
PRINT_DEBUG (("map_state: %s\n",
attr.map_state == IsViewable ? "IsViewable":
@@ -899,7 +878,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);
}
@@ -997,3 +976,17 @@ hide_others (rp_window *win)
hide_window (cur);
}
}
+
+/* Hide any window displayed on the given screen */
+void
+hide_screen_windows (rp_screen *s)
+{
+ rp_frame *cur_frame;
+ rp_window *cur_win;
+
+ list_for_each_entry (cur_frame, &s->frames, node)
+ {
+ cur_win = find_window_number (cur_frame->win_number);
+ hide_window (cur_win);
+ }
+}
diff --git a/src/manage.h b/src/manage.h
index 6d5f1f5..6788485 100644
--- a/src/manage.h
+++ b/src/manage.h
@@ -28,8 +28,7 @@ void clear_unmanaged_list (void);
char *list_unmanaged_windows (void);
void add_unmanaged_window (char *name);
int unmanaged_window (Window w);
-rp_screen* current_screen (void);
-void scanwins(rp_screen *s);
+void scanwins (void);
void unmanage (rp_window *w);
int update_window_name (rp_window *win);
void update_normal_hints (rp_window *win);
@@ -56,5 +55,6 @@ void unhide_all_windows (void);
void unhide_window_below (rp_window *win);
void withdraw_window (rp_window *win);
void hide_others (rp_window *win);
+void hide_screen_windows (rp_screen *s);
#endif /* ! _RATPOISION_MANAGE_H */
diff --git a/src/ratpoison.h b/src/ratpoison.h
index 4f8fdf7..3068050 100644
--- a/src/ratpoison.h
+++ b/src/ratpoison.h
@@ -76,11 +76,10 @@ do { \
#include "history.h"
#include "completions.h"
#include "hook.h"
-#include "xinerama.h"
+#include "xrandr.h"
#include "format.h"
void clean_up (void);
-rp_screen *find_screen (Window w);
void set_close_on_exec (int fd);
const char *get_homedir (void);
diff --git a/src/screen.c b/src/screen.c
index 0afdee0..2c36a6b 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1,4 +1,5 @@
/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Shawn Betts <sabetts@vcn.bc.ca>
+ * Copyright (C) 2016 Mathieu OTHACEHE <m.othacehe@gmail.com>
*
* 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,128 +154,220 @@ screen_find_frame_by_frame (rp_screen *s, rp_frame *f)
rp_screen *
find_screen (Window w)
{
- int i;
+ rp_screen *cur;
+
+ list_for_each_entry (cur, &rp_screens, node)
+ {
+ if (cur->root == w)
+ return cur;
+ }
+
+ return NULL;
+}
+
+/* Given a window attr, return the rp_screen struct */
+rp_screen *
+find_screen_by_attr (XWindowAttributes attr)
+{
+ 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 (attr.x >= cur->left &&
+ attr.x <= cur->left + cur->width &&
+ attr.y >= cur->top &&
+ attr.y <= cur->top + cur->height)
+ 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_number (int number)
+{
+ rp_screen *cur;
+
+ list_for_each_entry (cur, &rp_screens, node)
+ {
+ if (cur->number == number)
+ return cur;
+ }
+
+ return NULL;
+}
+
+static int
+screen_cmp (void *priv UNUSED, 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;
+ if (sc_a->left > sc_b->left)
+ return 1;
+
+ if (sc_a->top > sc_b->top)
+ return -1;
+ if (sc_a->top < sc_b->top)
+ 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);
+}
- /* Get the number of screens */
- if (rp_have_xinerama)
- num_screens = xine_screen_count;
- else
- num_screens = ScreenCount (dpy);
+static void
+screen_set_numbers (void)
+{
+ rp_screen *cur;
- /* make sure the screen specified is valid. */
- if (screen_arg)
+ list_for_each_entry (cur, &rp_screens, node)
{
- /* 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);
- }
+ cur->number = numset_request (rp_glob_screen.numset);
+ }
+}
- if (screen_num < 0 || screen_num >= num_screens)
- {
- fprintf (stderr, "%d is an invalid screen for the display\n", screen_num);
- exit (EXIT_FAILURE);
- }
+static void
+screen_select_primary (void)
+{
+ rp_screen *cur;
+
+ /* By default, take the first screen as current screen */
+ list_first(cur, &rp_screens, node);
+ if (!rp_current_screen)
+ rp_current_screen = cur;
+
+#ifdef HAVE_XRANDR
+ if (!rp_have_xrandr)
+ return;
- /* we're only going to use one screen. */
- num_screens = 1;
+ list_for_each_entry (cur, &rp_screens, node)
+ {
+ if (xrandr_is_primary(cur)) {
+ rp_current_screen = cur;
+ PRINT_DEBUG(("Xrandr primary screen %d detected\n",
+ rp_current_screen->number));
+ break;
+ }
}
+#endif
+}
+
+static void
+init_global_screen (rp_global_screen *s)
+{
+ int screen_num;
+
+ screen_num = DefaultScreen (dpy);
+ s->root = RootWindow (dpy, screen_num);
+
+ s->numset = numset_new ();
+ 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);
+}
+
+void
+init_screens (void)
+{
+ int i;
+ int screen_count = 0;
+ int *rr_outputs = NULL;
+ rp_screen *screen;
+
+ /* Get the number of screens */
+ if (rp_have_xrandr) {
+#ifdef HAVE_XRANDR
+ 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_XRANDR
+ if (rp_have_xrandr)
+ xrandr_fill_screen (rr_outputs[i], screen);
+#endif
+ init_screen (screen);
}
+ screen_sort ();
+ screen_set_numbers ();
+ screen_select_primary ();
+
+ free (rr_outputs);
}
static void
init_rat_cursor (rp_screen *s)
{
- s->rat = XCreateFontCursor( dpy, XC_icon );
+ s->rat = XCreateFontCursor (dpy, XC_icon);
}
static void
-init_screen (rp_screen *s, int screen_num)
+init_screen (rp_screen *s)
{
XGCValues gcv;
struct sbuf *buf;
- int xine_screen_num;
char *colon;
+ int screen_num;
- /* We use screen_num below to refer to the real X screen number, but
- * if we're using Xinerama, it will only be the Xinerama logical screen
- * number. So we shuffle it away and replace it with the real one now,
- * to cause confusion. -- CP
- */
- if (rp_have_xinerama)
- {
- xine_screen_num = screen_num;
- screen_num = DefaultScreen(dpy);
- xinerama_get_screen_info(xine_screen_num,
- &s->left, &s->top, &s->width, &s->height);
- }
- else
+ screen_num = DefaultScreen (dpy);
+
+ if (!rp_have_xrandr)
{
- xine_screen_num = screen_num;
s->left = 0;
s->top = 0;
- s->width = DisplayWidth(dpy, screen_num);
- s->height = DisplayHeight(dpy, screen_num);
+ s->width = DisplayWidth (dpy, screen_num);
+ s->height = DisplayHeight (dpy, screen_num);
}
/* Select on some events on the root window, if this fails, then
there is already a WM running and the X Error handler will catch
it, terminating ratpoison. */
- XSelectInput(dpy, RootWindow (dpy, screen_num),
- PropertyChangeMask | ColormapChangeMask
- | SubstructureRedirectMask | SubstructureNotifyMask
- | StructureNotifyMask);
+ XSelectInput (dpy, RootWindow (dpy, screen_num),
+ PropertyChangeMask | ColormapChangeMask
+ | SubstructureRedirectMask | SubstructureNotifyMask
+ | StructureNotifyMask);
XSync (dpy, False);
/* Set the numset for the frames to our global numset. */
s->frames_numset = rp_frame_numset;
+ s->scratch_buffer = NULL;
+
/* Build the display string for each screen */
buf = sbuf_new (0);
sbuf_printf (buf, "DISPLAY=%s", DisplayString (dpy));
@@ -295,21 +388,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 +404,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 +415,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 +478,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 +496,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
@@ -427,20 +514,17 @@ is_rp_window_for_given_screen (Window w, rp_screen *s)
}
int
-is_rp_window_for_screen(Window w, rp_screen *s)
+is_rp_window (Window w)
{
- 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 +534,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",
+ screen->number,
+ 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 +552,68 @@ screen_dump (rp_screen *screen)
return tmp;
}
+int
+screen_count (void)
+{
+ return list_size (&rp_screens);
+}
+
+rp_screen *
+screen_next (void)
+{
+ return list_next_entry (rp_current_screen, &rp_screens, node);
+}
+
+rp_screen *
+screen_prev (void)
+{
+ return list_prev_entry (rp_current_screen, &rp_screens, node);
+}
+
+static void
+screen_remove_current (void)
+{
+ 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;
- }
+ PRINT_DEBUG (("screen_update (left=%d, top=%d, width=%d, height=%d)\n",
+ left, top, width, height));
- if (s->width == width && s->height == height)
+ if (s->width == width &&
+ s->height == height &&
+ s->left == left &&
+ s->top == top)
/* nothing to do */
return;
- oldwidth = s->width; oldheight = s->height;
- s->width = width; s->height = height;
+ oldwidth = s->width;
+ oldheight = s->height;
- XResizeWindow (dpy, s->help_window, width, height);
+ s->left = left;
+ s->top = top;
+ s->width = width;
+ s->height = height;
+
+ XMoveResizeWindow (dpy, s->help_window, s->left, s->top, s->width, s->height);
list_for_each_entry (f, &s->frames, node)
{
@@ -496,3 +624,115 @@ 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);
+
+ screen->number = numset_request (rp_glob_screen.numset);
+
+#ifdef HAVE_XRANDR
+ if (rp_have_xrandr)
+ xrandr_fill_screen (rr_output, screen);
+#endif
+ init_screen (screen);
+ init_frame_list (screen);
+
+ if (screen_count () == 1)
+ {
+ rp_current_screen = screen;
+ change_windows_screen (NULL, rp_current_screen);
+ set_window_focus (rp_current_screen->key_window);
+ }
+
+ return screen;
+}
+
+void
+screen_del (rp_screen *s)
+{
+ if (s == rp_current_screen)
+ {
+ if (screen_count () == 1)
+ {
+ hide_screen_windows (s);
+ rp_current_screen = NULL;
+ }
+ else
+ {
+ /*
+ * The deleted screen cannot be the current screen anymore,
+ * focus the next one.
+ */
+ screen_remove_current ();
+ }
+ }
+ else
+ {
+ hide_screen_windows (s);
+ }
+
+ /* Affect window's screen backpointer to the new current screen */
+ change_windows_screen (s, rp_current_screen);
+
+ numset_release (rp_glob_screen.numset, s->number);
+
+ 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);
+
+ numset_free (rp_glob_screen.numset);
+}
diff --git a/src/screen.h b/src/screen.h
index 6bad555..fdc0748 100644
--- a/src/screen.h
+++ b/src/screen.h
@@ -35,14 +35,32 @@ 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);
+rp_screen *find_screen (Window w);
+rp_screen *find_screen_by_attr (XWindowAttributes w);
+
+void init_screens (void);
void activate_screen (rp_screen *s);
void deactivate_screen (rp_screen *s);
-int is_rp_window_for_screen (Window w, rp_screen *s);
+int is_rp_window (Window w);
int is_a_root_window (unsigned int w);
char *screen_dump (rp_screen *screen);
-void screen_update (rp_screen *s, int width, int height);
+void screen_update (rp_screen *s, int left, int top, int width, int height);
+
+int screen_count (void);
+
+rp_screen *screen_next(void);
+rp_screen *screen_prev(void);
+
+rp_screen *screen_number (int number);
+
+void screen_sort(void);
+
+rp_screen *screen_add(int rr_output);
+void screen_del(rp_screen *s);
+void screen_free (rp_screen *s);
+void screen_free_final(void);
+
#endif
diff --git a/src/split.c b/src/split.c
index b36b99e..7042a55 100644
--- a/src/split.c
+++ b/src/split.c
@@ -41,24 +41,10 @@ update_last_access (rp_frame *frame)
rp_frame *
current_frame (void)
{
- rp_screen *s = current_screen();
+ rp_screen *s = rp_current_screen;
return screen_get_frame (s, s->current_frame);
}
-int
-num_frames (rp_screen *s)
-{
- int count = 0;
- rp_frame *cur;
-
- list_for_each_entry (cur, &s->frames, node)
- {
- count++;
- }
-
- return count;
-}
-
void
cleanup_frame (rp_frame *frame)
{
@@ -95,7 +81,7 @@ set_frames_window (rp_frame *frame, rp_window *win)
win->frame_number = frame->number;
/* We need to make sure that win and frame are on the same screen,
- * since with Xinerama, windows can move from one screen to another.
+ * since with Xrandr, windows can move from one screen to another.
*/
win->scr = frames_screen(frame);
}
@@ -110,15 +96,17 @@ set_frames_window (rp_frame *frame, rp_window *win)
rp_screen *
frames_screen (rp_frame *frame)
{
- int i;
- rp_frame *cur;
+ rp_frame *cur_frame;
+ rp_screen *cur_screen;
- for (i=0; i<num_screens; i++)
- list_for_each_entry (cur, &screens[i].frames, node)
- {
- if (frame == cur)
- return &screens[i];
- }
+ list_for_each_entry (cur_screen, &rp_screens, node)
+ {
+ list_for_each_entry (cur_frame, &cur_screen->frames, node)
+ {
+ if (frame == cur_frame)
+ return cur_screen;
+ }
+ }
/* This SHOULD be impossible to get to. FIXME: It'll crash higher up if we
return NULL. */
@@ -171,10 +159,12 @@ create_initial_frame (rp_screen *screen)
void
init_frame_lists (void)
{
- int i;
+ rp_screen *cur;
- for (i=0; i<num_screens; i++)
- init_frame_list (&screens[i]);
+ list_for_each_entry (cur, &rp_screens, node)
+ {
+ init_frame_list (cur);
+ }
}
void
@@ -188,21 +178,19 @@ init_frame_list (rp_screen *screen)
rp_frame *
find_last_frame (void)
{
- rp_frame *cur, *last = NULL;
+ rp_frame *cur_frame, *last = NULL;
+ rp_screen *cur_screen;
int last_access = -1;
- int i;
- for (i=0; i<num_screens; i++)
+ list_for_each_entry (cur_screen, &rp_screens, node)
{
- rp_screen *s = &screens[i];
-
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (cur_frame, &cur_screen->frames, node)
{
- if (cur->number != current_screen()->current_frame
- && cur->last_access > last_access)
+ if (cur_frame->number != rp_current_screen->current_frame &&
+ cur_frame->last_access > last_access)
{
- last_access = cur->last_access;
- last = cur;
+ last_access = cur_frame->last_access;
+ last = cur_frame;
}
}
}
@@ -227,6 +215,12 @@ find_windows_frame (rp_window *win)
return NULL;
}
+int
+num_frames (rp_screen *s)
+{
+ return list_size (&s->frames);
+}
+
rp_frame *
find_frame_next (rp_frame *frame)
{
@@ -277,7 +271,7 @@ find_window_for_frame (rp_frame *frame)
list_for_each_entry (cur, &rp_current_group->mapped_windows, node)
{
- if ((cur->win->scr == s || rp_have_xinerama)
+ if ((cur->win->scr == s || rp_have_xrandr)
&& cur->win != current_window()
&& !find_windows_frame (cur->win)
&& cur->win->last_access >= last_access
@@ -382,7 +376,7 @@ void
remove_all_splits (void)
{
struct list_head *tmp, *iter;
- rp_screen *s = current_screen();
+ rp_screen *s = rp_current_screen;
rp_frame *frame;
rp_window *win;
@@ -822,9 +816,9 @@ remove_frame (rp_frame *frame)
void
set_active_frame (rp_frame *frame, int force_indicator)
{
- rp_screen *old_s = current_screen();
+ rp_screen *old_s = rp_current_screen;
rp_screen *s = frames_screen (frame);
- int old = current_screen()->current_frame;
+ int old = rp_current_screen->current_frame;
rp_window *win, *old_win;
rp_frame *old_frame;
@@ -845,7 +839,7 @@ set_active_frame (rp_frame *frame, int force_indicator)
s->current_frame = frame->number;
/* If frame->win == NULL, then rp_current_screen is not updated. */
- rp_current_screen = s->xine_screen_num;
+ rp_current_screen = s;
update_bar (s);
@@ -926,15 +920,18 @@ blank_frame (rp_frame *frame)
void
hide_frame_indicator (void)
{
- int i;
- for (i=0; i<num_screens; i++)
- XUnmapWindow (dpy, screens[i].frame_window);
+ rp_screen *cur;
+
+ list_for_each_entry (cur, &rp_screens, node)
+ {
+ XUnmapWindow (dpy, cur->frame_window);
+ }
}
void
show_frame_indicator (int force)
{
- if (num_frames (current_screen()) > 1 || force)
+ if (num_frames (rp_current_screen) > 1 || force)
{
hide_frame_indicator ();
show_frame_message (defaults.frame_fmt);
@@ -945,7 +942,7 @@ show_frame_indicator (int force)
void
show_frame_message (char *msg)
{
- rp_screen *s = current_screen ();
+ rp_screen *s = rp_current_screen;
int width, height;
rp_frame *frame;
rp_window *win;
@@ -1000,15 +997,16 @@ show_frame_message (char *msg)
rp_frame *
find_frame_up (rp_frame *frame)
{
- rp_screen *s = frames_screen (frame);
+ rp_screen *s;
rp_frame *cur;
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (s, &rp_screens, node)
{
- if (frame->y == cur->y + cur->height)
+ list_for_each_entry (cur, &s->frames, node)
{
- if (frame->x >= cur->x && frame->x < cur->x + cur->width)
- return cur;
+ if (frame_top_abs (frame) == frame_bottom_abs (cur))
+ if (frame_right_abs (frame) >= frame_left_abs (cur) && frame_left_abs (frame) <= frame_right_abs (cur))
+ return cur;
}
}
@@ -1018,15 +1016,16 @@ find_frame_up (rp_frame *frame)
rp_frame *
find_frame_down (rp_frame *frame)
{
- rp_screen *s = frames_screen (frame);
+ rp_screen *s;
rp_frame *cur;
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (s, &rp_screens, node)
{
- if (frame->y + frame->height == cur->y)
+ list_for_each_entry (cur, &s->frames, node)
{
- if (frame->x >= cur->x && frame->x < cur->x + cur->width)
- return cur;
+ if (frame_bottom_abs (frame) == frame_top_abs (cur))
+ if (frame_right_abs (frame) >= frame_left_abs (cur) && frame_left_abs (frame) <= frame_right_abs (cur))
+ return cur;
}
}
@@ -1036,15 +1035,16 @@ find_frame_down (rp_frame *frame)
rp_frame *
find_frame_left (rp_frame *frame)
{
- rp_screen *s = frames_screen (frame);
+ rp_screen *s;
rp_frame *cur;
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (s, &rp_screens, node)
{
- if (frame->x == cur->x + cur->width)
+ list_for_each_entry (cur, &s->frames, node)
{
- if (frame->y >= cur->y && frame->y < cur->y + cur->height)
- return cur;
+ if (frame_left_abs (frame) == frame_right_abs (cur))
+ if (frame_top_abs (frame) >= frame_top_abs (cur) && frame_top_abs (frame) < frame_bottom_abs (cur))
+ return cur;
}
}
@@ -1054,15 +1054,16 @@ find_frame_left (rp_frame *frame)
rp_frame *
find_frame_right (rp_frame *frame)
{
- rp_screen *s = frames_screen (frame);
+ rp_screen *s;
rp_frame *cur;
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (s, &rp_screens, node)
{
- if (frame->x + frame->width == cur->x)
+ list_for_each_entry (cur, &s->frames, node)
{
- if (frame->y >= cur->y && frame->y < cur->y + cur->height)
- return cur;
+ if (frame_right_abs (frame) == frame_left_abs (cur))
+ if (frame_top_abs (frame) >= frame_top_abs (cur) && frame_top_abs (frame) < frame_bottom_abs (cur))
+ return cur;
}
}
@@ -1072,17 +1073,15 @@ find_frame_right (rp_frame *frame)
rp_frame *
find_frame_number (int num)
{
- int i;
- rp_frame *cur;
+ rp_frame *cur_frame;
+ rp_screen *cur_screen;
- for (i=0; i<num_screens; i++)
+ list_for_each_entry (cur_screen, &rp_screens, node)
{
- rp_screen *s = &screens[i];
-
- list_for_each_entry (cur, &s->frames, node)
+ list_for_each_entry (cur_frame, &cur_screen->frames, node)
{
- if (cur->number == num)
- return cur;
+ if (cur_frame->number == num)
+ return cur_frame;
}
}
diff --git a/src/split.h b/src/split.h
index 87bb660..f125df6 100644
--- a/src/split.h
+++ b/src/split.h
@@ -22,7 +22,6 @@
#ifndef SPLIT_H
#define SPLIT_H
-int num_frames (rp_screen *s);
rp_window *set_frames_window (rp_frame *frame, rp_window *win);
void cleanup_frame (rp_frame *frame);
void maximize_all_windows_in_frame (rp_frame *frame);
@@ -35,6 +34,7 @@ void resize_frame_vertically (rp_frame *frame, int diff);
void remove_frame (rp_frame *frame);
rp_window *find_window_for_frame (rp_frame *frame);
rp_frame *find_windows_frame (rp_window *win);
+int num_frames (rp_screen *s);
rp_frame *find_frame_next (rp_frame *frame);
rp_frame *find_frame_prev (rp_frame *frame);
rp_window *current_window (void);
diff --git a/src/window.c b/src/window.c
index 7d31a87..b7609ca 100644
--- a/src/window.c
+++ b/src/window.c
@@ -412,7 +412,7 @@ give_window_focus (rp_window *win, rp_window *last_win)
if (last_win != NULL && win != last_win)
{
save_mouse_position (last_win);
- XSetWindowBorder (dpy, last_win->w, last_win->scr->bw_color);
+ XSetWindowBorder (dpy, last_win->w, rp_glob_screen.bw_color);
}
if (win == NULL) return;
@@ -432,10 +432,10 @@ give_window_focus (rp_window *win, rp_window *last_win)
if (last_win != NULL) XUninstallColormap (dpy, last_win->colormap);
XInstallColormap (dpy, win->colormap);
- XSetWindowBorder (dpy, win->w, win->scr->fw_color);
+ XSetWindowBorder (dpy, win->w, rp_glob_screen.fw_color);
/* Finally, give the window focus */
- rp_current_screen = win->scr->xine_screen_num;
+ rp_current_screen = win->scr;
set_rp_window_focus (win);
XSync (dpy, False);
@@ -456,31 +456,17 @@ static rp_frame *
find_frame_non_dedicated(rp_screen *current_screen, rp_frame *current_frame)
{
rp_frame *cur;
+ rp_screen *screen;
- /* Try the only / current screen... */
- for (cur = list_next_entry (current_frame, &current_screen->frames, node);
- cur != current_frame;
- cur = list_next_entry (cur, &current_screen->frames, node))
- {
- if (!cur->dedicated)
- return cur;
- }
-
- /* If we have Xinerama, we can check *all* screens... */
- if (rp_have_xinerama)
+ list_for_each_entry (screen, &rp_screens, node)
{
- int i;
+ if (current_screen == screen)
+ continue;
- for (i = 0; i < num_screens; i++)
+ list_for_each_entry (cur, &screen->frames, node)
{
- if (current_screen == &screens[i])
- continue;
-
- list_for_each_entry (cur, &screens[i].frames, node)
- {
- if (!cur->dedicated)
- return cur;
- }
+ if (!cur->dedicated)
+ return cur;
}
}
@@ -492,36 +478,30 @@ set_active_window_body (rp_window *win, int force)
{
rp_window *last_win;
rp_frame *frame = NULL, *last_frame = NULL;
- rp_screen *screen;
if (win == NULL)
return;
PRINT_DEBUG (("intended_frame_number: %d\n", win->intended_frame_number));
- /* With Xinerama, we can move a window over to the current screen; otherwise
- * we have to switch to the screen that the window belongs to.
- */
- screen = rp_have_xinerama ? current_screen () : win->scr;
-
/* use the intended frame if we can. */
if (win->intended_frame_number >= 0)
{
- frame = screen_get_frame (screen, win->intended_frame_number);
+ frame = screen_get_frame (rp_current_screen, win->intended_frame_number);
win->intended_frame_number = -1;
if (frame != current_frame ())
last_frame = current_frame ();
}
if (frame == NULL)
- frame = screen_get_frame (screen, screen->current_frame);
+ frame = screen_get_frame (rp_current_screen, rp_current_screen->current_frame);
if (frame->dedicated && !force)
{
/* Try to find a non-dedicated frame. */
rp_frame *non_dedicated;
- non_dedicated = find_frame_non_dedicated (screen, frame);
+ non_dedicated = find_frame_non_dedicated (rp_current_screen, frame);
if (non_dedicated != NULL)
{
last_frame = frame;
@@ -594,7 +574,7 @@ get_window_list (char *fmt, char *delim, struct sbuf *buffer,
if (buffer == NULL) return;
sbuf_clear (buffer);
- find_window_other (current_screen());
+ find_window_other (rp_current_screen);
/* We only loop through the current group to look for windows. */
list_for_each_entry (we,&rp_current_group->mapped_windows,node)
@@ -671,3 +651,15 @@ win_get_frame (rp_window *win)
else
return NULL;
}
+
+void
+change_windows_screen (rp_screen *old_screen, rp_screen *new_screen)
+{
+ rp_window *win;
+
+ list_for_each_entry (win, &rp_mapped_window, node)
+ {
+ if (win->scr == old_screen)
+ win->scr = new_screen;
+ }
+}
diff --git a/src/window.h b/src/window.h
index fdd246c..4ec8ec8 100644
--- a/src/window.h
+++ b/src/window.h
@@ -61,5 +61,6 @@ void set_active_window_force (rp_window *win);
void set_active_window_body (rp_window *win, int force);
struct rp_child_info *get_child_info (Window w);
+void change_windows_screen (rp_screen *s, rp_screen *new_screen);
#endif /* ! _RATPOISON_LIST_H */
diff --git a/src/xinerama.c b/src/xinerama.c
deleted file mode 100644
index a8bceb2..0000000
--- a/src/xinerama.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* functions for grabbing information about Xinerama screens
- * Copyright (C) 2003 Cameron Patrick
- *
- * This file is part of ratpoison.
- *
- * ratpoison is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * ratpoison is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307 USA
- */
-
-#include "ratpoison.h"
-
-#ifdef HAVE_X11_EXTENSIONS_XINERAMA_H
-# include <X11/extensions/Xinerama.h>
-# define XINERAMA
-#endif
-
-int rp_have_xinerama = 0;
-int xine_screen_count;
-
-#ifdef XINERAMA
-static XineramaScreenInfo *xine_screens = NULL;
-#endif
-
-void
-init_xinerama(void)
-{
-#ifdef XINERAMA
- int evbase, errbase, major, minor;
-
- rp_have_xinerama = 0;
-
- if (xine_screens) XFree(xine_screens);
-
- if (!XineramaQueryExtension(dpy, &evbase, &errbase)) {
- return;
- }
-
- if (XineramaQueryVersion(dpy, &major, &minor) == 0) {
- return;
- }
-
- if (major != 1) {
- fprintf (stderr, "Warning: Xinerama version %d.%d not supported\n", major, minor);
- return;
- }
-
- if (!XineramaIsActive(dpy)) {
- return;
- }
-
- xine_screens = XineramaQueryScreens(dpy, &xine_screen_count);
- if (xine_screens == NULL) {
- return;
- }
- if (xine_screen_count < 2) {
- XFree (xine_screens);
- xine_screens = NULL;
- return;
- }
-
- rp_have_xinerama = 1;
-#else
- rp_have_xinerama = 0;
-#endif
-}
-
-#ifdef XINERAMA
-void xinerama_get_screen_info(int sc, int *x, int *y, int *w, int *h)
-{
- if ((sc < xine_screen_count) && (sc >= 0)) {
- *x = xine_screens[sc].x_org;
- *y = xine_screens[sc].y_org;
- *w = xine_screens[sc].width;
- *h = xine_screens[sc].height;
- }
-}
-#else
-void xinerama_get_screen_info(int sc UNUSED, int *x UNUSED, int *y UNUSED, int *w UNUSED, int *h UNUSED)
-{
-}
-#endif
-
-void
-free_xinerama(void)
-{
-#ifdef XINERAMA
- if (xine_screens) {
- XFree(xine_screens);
- }
- rp_have_xinerama = 0;
-#endif
-}
diff --git a/src/xrandr.c b/src/xrandr.c
new file mode 100644
index 0000000..de0cde3
--- /dev/null
+++ b/src/xrandr.c
@@ -0,0 +1,265 @@
+/* functions for grabbing information about xrandr screens
+ * Copyright (C) 2016 Mathieu OTHACEHE <m.othacehe@gmail.com>
+ *
+ * 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 3
+
+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);
+
+ rp_have_xrandr = 1;
+}
+
+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;
+}
+
+int
+xrandr_is_primary (rp_screen *screen)
+{
+ return screen->xrandr.primary;
+}
+
+void
+xrandr_fill_screen (int rr_output, rp_screen *screen)
+{
+ XRRScreenResources *res;
+ XRROutputInfo *outinfo;
+ XRRCrtcInfo *crtinfo;
+ RROutput primary;
+
+ 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;
+
+ primary = XRRGetOutputPrimary (dpy, RootWindow (dpy, DefaultScreen (dpy)));
+ if (rr_output == primary)
+ screen->xrandr.primary = 1;
+ else
+ screen->xrandr.primary = 0;
+
+ 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 = screen_add (ev->output);
+ screen_sort ();
+ PRINT_DEBUG (("%s: Added screen %s with crtc %lu\n", __func__,
+ sbuf_get (screen->xrandr.name),
+ (unsigned long)outinfo->crtc));
+ } else if (screen && !outinfo->crtc) {
+ PRINT_DEBUG (("%s: Removing screen %s\n", __func__,
+ sbuf_get (screen->xrandr.name)));
+ screen_del (screen);
+ }
+
+ XRRFreeOutputInfo (outinfo);
+ XRRFreeScreenResources (res);
+}
+
+#ifdef DEBUG
+static const char *
+xrandr_rotation_string (Rotation r)
+{
+ static char buf[64];
+
+#define CASE(c) case c : return #c
+ switch (r)
+ {
+ CASE(RR_Rotate_0);
+ CASE(RR_Rotate_90);
+ CASE(RR_Rotate_180);
+ CASE(RR_Rotate_270);
+#undef CASE
+ default:
+ snprintf(buf, sizeof buf, "Unknown rotation %hu", (unsigned short)r);
+ return buf;
+ }
+}
+#endif
+
+static void
+xrandr_crtc_change (XRRCrtcChangeNotifyEvent *ev)
+{
+ rp_screen *screen;
+
+ if (!ev->crtc || !ev->width || !ev->height)
+ return;
+
+ screen = xrandr_screen_crtc (ev->crtc);
+
+ PRINT_DEBUG (("%s: crtc %s, rotation %s "
+ "ev->x %d, ev->y %d, ev->width %d, ev->height %d\n",
+ __func__, screen ? "found" : "not found",
+ xrandr_rotation_string (ev->rotation),
+ ev->x, ev->y, ev->width, ev->height));
+
+ if (!screen)
+ return;
+
+ if (ev->rotation == RR_Rotate_90 || ev->rotation == RR_Rotate_270)
+ screen_update (screen, ev->x, ev->y, ev->height, ev->width);
+ else
+ screen_update (screen, ev->x, ev->y, ev->width, ev->height);
+}
+
+void
+xrandr_notify (XEvent *ev)
+{
+ XRRNotifyEvent *n_event;
+ XRROutputChangeNotifyEvent *o_event;
+ XRRCrtcChangeNotifyEvent *c_event;
+
+ if (ev->type != xrandr_evbase + RRNotify)
+ return;
+
+ PRINT_DEBUG (("--- Handling RRNotify ---\n"));
+
+ n_event = (XRRNotifyEvent *)ev;
+ switch (n_event->subtype) {
+ case RRNotify_OutputChange:
+ PRINT_DEBUG (("--- XRROutputChangeNotifyEvent ---\n"));
+ o_event = (XRROutputChangeNotifyEvent *)ev;
+ xrandr_output_change (o_event);
+ break;
+ case RRNotify_CrtcChange:
+ PRINT_DEBUG (("--- XRRCrtcChangeNotifyEvent ---\n"));
+ c_event = (XRRCrtcChangeNotifyEvent *)ev;
+ xrandr_crtc_change (c_event);
+ break;
+ case RRNotify_OutputProperty:
+ PRINT_DEBUG (("--- RRNotify_OutputProperty ---\n"));
+ break;
+ default:
+ PRINT_DEBUG (("--- Unknown subtype %d ---\n", n_event->subtype));
+ break;
+ }
+}
diff --git a/src/xinerama.h b/src/xrandr.h
index 233ec46..25ff830 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,15 @@
* 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);
+int xrandr_is_primary (rp_screen *screen);
+void xrandr_fill_screen(int rr_output, rp_screen *screen);
+void xrandr_notify(XEvent *ev);
#endif