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