diff options
author | Jérémie Courrèges-Anglas <jca@wxcvbn.org> | 2017-02-15 16:25:34 +0100 |
---|---|---|
committer | Jérémie Courrèges-Anglas <jca@wxcvbn.org> | 2017-02-15 16:25:34 +0100 |
commit | 2dbe923ea51cc9a13f4c20091e1bfd86f56f9688 (patch) | |
tree | 3dd7587776ff1679dac0aee80913244d2dd0cad4 | |
parent | c24d1e39ea14666f86c286d72d7f88c9028b3094 (diff) | |
parent | 2bda8bc2933dc3be318fbb7d1e290cd6ff4b1262 (diff) | |
download | ratpoison-2dbe923ea51cc9a13f4c20091e1bfd86f56f9688.zip |
Merge branch 'xrandr'
All the hard work on xrandr done by Mathieu OTHACEHE, thanks!
-rw-r--r-- | configure.ac | 40 | ||||
-rw-r--r-- | doc/ratpoison.texi | 4 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/actions.c | 377 | ||||
-rw-r--r-- | src/bar.c | 8 | ||||
-rw-r--r-- | src/communications.c | 11 | ||||
-rw-r--r-- | src/communications.h | 2 | ||||
-rw-r--r-- | src/data.h | 34 | ||||
-rw-r--r-- | src/events.c | 81 | ||||
-rw-r--r-- | src/format.c | 10 | ||||
-rw-r--r-- | src/frame.c | 27 | ||||
-rw-r--r-- | src/frame.h | 4 | ||||
-rw-r--r-- | src/globals.c | 31 | ||||
-rw-r--r-- | src/globals.h | 13 | ||||
-rw-r--r-- | src/group.c | 18 | ||||
-rw-r--r-- | src/input.c | 10 | ||||
-rw-r--r-- | src/linkedlist.c | 139 | ||||
-rw-r--r-- | src/linkedlist.h | 6 | ||||
-rw-r--r-- | src/main.c | 95 | ||||
-rw-r--r-- | src/manage.c | 61 | ||||
-rw-r--r-- | src/manage.h | 4 | ||||
-rw-r--r-- | src/ratpoison.h | 3 | ||||
-rw-r--r-- | src/screen.c | 486 | ||||
-rw-r--r-- | src/screen.h | 24 | ||||
-rw-r--r-- | src/split.c | 149 | ||||
-rw-r--r-- | src/split.h | 2 | ||||
-rw-r--r-- | src/window.c | 60 | ||||
-rw-r--r-- | src/window.h | 1 | ||||
-rw-r--r-- | src/xinerama.c | 104 | ||||
-rw-r--r-- | src/xrandr.c | 265 | ||||
-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); @@ -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 */ @@ -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)); @@ -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, ¤t_screen->frames, node); - cur != current_frame; - cur = list_next_entry (cur, ¤t_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 |