#! /bin/sh -e
#
## DP: From: Bert Wesarg <bert.wesarg@googlemail.com>
## DP: Subject: [PATCH] keys to move windows to another xinerama screen
## DP: New key actions to move a window between xinerama screens. The new position
## DP: will be relatively the same as on the old screen. I.e. if the window was
## DP: centered, its centered again, if it was in the lower left corner, it will be
## DP: again in the lower left corner. Maximazations states will be restored.
## DP: Fullscreen too, but this wont work well with mplayer in fullscreen.

if [ $# -lt 1 ]; then
    echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
    exit 1
fi

[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts
patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}"

case "$1" in
    -patch) patch -p1 ${patch_opts} < $0;;
    -unpatch) patch -R -p1 ${patch_opts} < $0;;
    *)
        echo "`basename $0`: script expects -patch|-unpatch as argument" >&2
        exit 1;;
esac

exit 0

@DPATCH@
diff --git a/src/bindkey.h b/src/bindkey.h
index 6ea53b7..29cd228 100644
--- a/src/bindkey.h
+++ b/src/bindkey.h
@@ -37,6 +37,21 @@
 #define defgKeyWinSnapMoveW             XK_KP_Left, kfCtrl+kfAlt+kfShift, "Ctrl+Alt+Shift+KP_4"
 #define defgKeyWinSnapMoveNW            XK_KP_Home, kfCtrl+kfAlt+kfShift, "Ctrl+Alt+Shift+KP_7"
 #define defgKeyWinSmartPlace            XK_KP_Begin, kfCtrl+kfAlt+kfShift, "Ctrl+Alt+Shift+KP_5"
+#define defgKeyWinScreenPrimary         XK_Home, kfCtrl+kfAlt, "Ctrl+Alt+Home"
+#define defgKeyWinScreenNext            XK_End, kfCtrl+kfAlt, "Ctrl+Alt+Page_Up"
+#define defgKeyWinScreenPrev            XK_End, kfCtrl+kfAlt, "Ctrl+Alt+Page_Down"
+#define defgKeyWinScreen1               0, 0, ""
+#define defgKeyWinScreen2               0, 0, ""
+#define defgKeyWinScreen3               0, 0, ""
+#define defgKeyWinScreen4               0, 0, ""
+#define defgKeyWinScreen5               0, 0, ""
+#define defgKeyWinScreen6               0, 0, ""
+#define defgKeyWinScreen7               0, 0, ""
+#define defgKeyWinScreen8               0, 0, ""
+#define defgKeyWinScreen9               0, 0, ""
+#define defgKeyWinScreen10              0, 0, ""
+#define defgKeyWinScreen11              0, 0, ""
+#define defgKeyWinScreen12              0, 0, ""
 #define defgKeySysSwitchNext            XK_Tab, kfAlt, "Alt+Tab"
 #define defgKeySysSwitchLast            XK_Tab, kfAlt+kfShift, "Alt+Shift+Tab"
 #define defgKeySysWinNext               XK_Escape, kfAlt, "Alt+Esc"
@@ -154,6 +169,21 @@ DEF_WMKEY(gKeyWinSnapMoveSW);
 DEF_WMKEY(gKeyWinSnapMoveW);
 DEF_WMKEY(gKeyWinSnapMoveNW);
 DEF_WMKEY(gKeyWinSmartPlace);
+DEF_WMKEY(gKeyWinScreenPrimary);
+DEF_WMKEY(gKeyWinScreenNext);
+DEF_WMKEY(gKeyWinScreenPrev);
+DEF_WMKEY(gKeyWinScreen1);
+DEF_WMKEY(gKeyWinScreen2);
+DEF_WMKEY(gKeyWinScreen3);
+DEF_WMKEY(gKeyWinScreen4);
+DEF_WMKEY(gKeyWinScreen5);
+DEF_WMKEY(gKeyWinScreen6);
+DEF_WMKEY(gKeyWinScreen7);
+DEF_WMKEY(gKeyWinScreen8);
+DEF_WMKEY(gKeyWinScreen9);
+DEF_WMKEY(gKeyWinScreen10);
+DEF_WMKEY(gKeyWinScreen11);
+DEF_WMKEY(gKeyWinScreen12);
 DEF_WMKEY(gKeyWinMenu);
 DEF_WMKEY(gKeySysSwitchNext);
 DEF_WMKEY(gKeySysSwitchLast);
diff --git a/src/default.h b/src/default.h
index e967e64..c373a32 100644
--- a/src/default.h
+++ b/src/default.h
@@ -409,6 +409,21 @@ cfoption icewm_preferences[] = {
     OKV("KeyWinArrangeW",                       gKeyWinArrangeW,                ""),
     OKV("KeyWinArrangeNW",                      gKeyWinArrangeNW,               ""),
     OKV("KeyWinArrangeC",                       gKeyWinArrangeC,                ""),
+    OKV("KeyWinScreenPrimary",                  gKeyWinScreenPrimary,           "Move current window to the primary Xinerama screen"),
+    OKV("KeyWinScreenNext",                     gKeyWinScreenNext,              "Move current window to the next Xinerama screen"),
+    OKV("KeyWinScreenPrev",                     gKeyWinScreenPrev,              "Move current window to the previous Xinerama screen"),
+    OKV("KeyWinScreen1",                        gKeyWinScreen1,                 "Move current window to the first Xinerama screen"),
+    OKV("KeyWinScreen2",                        gKeyWinScreen2,                 "Move current window to the second Xinerama screen"),
+    OKV("KeyWinScreen3",                        gKeyWinScreen3,                 "Move current window to the 3rd Xinerama screen"),
+    OKV("KeyWinScreen4",                        gKeyWinScreen4,                 "Move current window to the 4th Xinerama screen"),
+    OKV("KeyWinScreen5",                        gKeyWinScreen5,                 "Move current window to the 5th Xinerama screen"),
+    OKV("KeyWinScreen6",                        gKeyWinScreen6,                 "Move current window to the 6th Xinerama screen"),
+    OKV("KeyWinScreen7",                        gKeyWinScreen7,                 "Move current window to the 7th Xinerama screen"),
+    OKV("KeyWinScreen8",                        gKeyWinScreen8,                 "Move current window to the 8th Xinerama screen"),
+    OKV("KeyWinScreen9",                        gKeyWinScreen9,                 "Move current window to the 9th Xinerama screen"),
+    OKV("KeyWinScreen10",                       gKeyWinScreen10,                "Move current window to the 10th Xinerama screen"),
+    OKV("KeyWinScreen11",                       gKeyWinScreen11,                "Move current window to the 11th Xinerama screen"),
+    OKV("KeyWinScreen12",                       gKeyWinScreen12,                "Move current window to the 12th Xinerama screen"),
     OKV("KeySysSwitchNext",                     gKeySysSwitchNext,              ""),
     OKV("KeySysSwitchLast",                     gKeySysSwitchLast,              ""),
     OKV("KeySysWinNext",                        gKeySysWinNext,                 ""),
diff --git a/src/movesize.cc b/src/movesize.cc
index fa15075..51df8fb 100644
--- a/src/movesize.cc
+++ b/src/movesize.cc
@@ -830,6 +830,36 @@ bool YFrameWindow::handleKey(const XKeyEvent &key) {
                         setCurrentPositionOuter(newX, newY);
                     }
                 }
+            } else if (IS_WMKEY(k, vm, gKeyWinScreenPrimary)) {
+                if (canMove()) moveToScreen(-1);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreenNext)) {
+                if (canMove()) moveToScreen(-2);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreenPrev)) {
+                if (canMove()) moveToScreen(-3);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen1)) {
+                if (canMove()) moveToScreen(0);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen2)) {
+                if (canMove()) moveToScreen(1);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen3)) {
+                if (canMove()) moveToScreen(2);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen4)) {
+                if (canMove()) moveToScreen(3);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen5)) {
+                if (canMove()) moveToScreen(4);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen6)) {
+                if (canMove()) moveToScreen(5);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen7)) {
+                if (canMove()) moveToScreen(6);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen8)) {
+                if (canMove()) moveToScreen(7);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen9)) {
+                if (canMove()) moveToScreen(8);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen10)) {
+                if (canMove()) moveToScreen(9);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen11)) {
+                if (canMove()) moveToScreen(10);
+            } else if (IS_WMKEY(k, vm, gKeyWinScreen12)) {
+                if (canMove()) moveToScreen(11);
             } else if (isIconic() || isRollup()) {
                 if (k == XK_Return || k == XK_KP_Enter) {
                     wmRestore();
diff --git a/src/wmframe.cc b/src/wmframe.cc
index 5dc8ba2..2d35bdb 100644
--- a/src/wmframe.cc
+++ b/src/wmframe.cc
@@ -591,6 +591,21 @@ void YFrameWindow::grabKeys() {
     GRAB_WMKEY(gKeyWinSnapMoveW);
     GRAB_WMKEY(gKeyWinSnapMoveNW);
     GRAB_WMKEY(gKeyWinSmartPlace);
+    GRAB_WMKEY(gKeyWinScreenPrimary);
+    GRAB_WMKEY(gKeyWinScreenNext);
+    GRAB_WMKEY(gKeyWinScreenPrev);
+    GRAB_WMKEY(gKeyWinScreen1);
+    GRAB_WMKEY(gKeyWinScreen2);
+    GRAB_WMKEY(gKeyWinScreen3);
+    GRAB_WMKEY(gKeyWinScreen4);
+    GRAB_WMKEY(gKeyWinScreen5);
+    GRAB_WMKEY(gKeyWinScreen6);
+    GRAB_WMKEY(gKeyWinScreen7);
+    GRAB_WMKEY(gKeyWinScreen8);
+    GRAB_WMKEY(gKeyWinScreen9);
+    GRAB_WMKEY(gKeyWinScreen10);
+    GRAB_WMKEY(gKeyWinScreen11);
+    GRAB_WMKEY(gKeyWinScreen12);
 
     container()->regrabMouse();
 }
@@ -3428,6 +3443,147 @@ int YFrameWindow::getScreen() {
     return manager->getScreenForRect(nx, ny, nw, nh);
 }
 
+void YFrameWindow::moveToScreen(int newScreen) {
+    int oldScreen = getScreen();
+
+    /* handle special screen num for primary/next/prev */
+    if (newScreen == -1)
+        newScreen = xineramaPrimaryScreen;
+    else if (newScreen == -2)
+        newScreen = manager->getNextScreen(oldScreen);
+    else if (newScreen == -3)
+        newScreen = manager->getPrevScreen(oldScreen);
+    else
+        newScreen = manager->verifyScreen(newScreen, oldScreen);
+
+    if (newScreen == oldScreen)
+        return;
+
+    MSG(("moveToScreen: %d => %d", oldScreen, newScreen));
+
+    long fOldState = fWinState;
+    setState(WinStateRollup |
+             WinStateHidden |
+             WinStateMaximizedVert |
+             WinStateMaximizedHoriz |
+             WinStateMinimized |
+             WinStateFullscreen, 0);
+
+    int oldScreenX1, oldScreenX2, oldScreenY1, oldScreenY2;
+    manager->getWorkArea(&oldScreenX1, &oldScreenY1, &oldScreenX2, &oldScreenY2, oldScreen);
+    MSG(("moveToScreen: [%+5d,%+5d]x[%+5d,%+5d]", oldScreenX1, oldScreenX2, oldScreenY1, oldScreenY2));
+
+    int newScreenX1, newScreenX2, newScreenY1, newScreenY2;
+    manager->getWorkArea(&newScreenX1, &newScreenY1, &newScreenX2, &newScreenY2, newScreen);
+    MSG(("moveToScreen: [%+5d,%+5d]x[%+5d,%+5d]", newScreenX1, newScreenX2, newScreenY1, newScreenY2));
+
+    /* remove and remember border{X,Y} */
+    bool borderLeft   = false,
+         borderRight  = false,
+         borderTop    = false,
+         borderBottom = false;
+    int oldX1 = x(),
+        oldX2 = x() + width(),
+        oldY1 = y(),
+        oldY2 = y() + height();
+
+    MSG(("moveToScreen: [%+5d,%+5d]x[%+5d,%+5d]", oldX1, oldX2, oldY1, oldY2));
+
+    if (oldX1 == (oldScreenX1 - borderX())) {
+        oldX1 = oldScreenX1;
+        borderLeft = true;
+    }
+    if (oldX2 == (oldScreenX2 + borderX())) {
+        oldX2 = oldScreenX2;
+        borderRight = true;
+    }
+    if (oldY1 == (oldScreenY1 - borderY())) {
+        oldY1 = oldScreenY1;
+        borderTop = true;
+    }
+    if (oldY2 == (oldScreenY2 + borderY())) {
+        oldY2 = oldScreenY2;
+        borderBottom = true;
+    }
+
+    MSG(("moveToScreen: [%+5d,%+5d]x[%+5d,%+5d]", oldX1, oldX2, oldY1, oldY2));
+
+    int oldScreenSpaceLeft,
+        oldScreenSpaceRight,
+        oldScreenSpaceTop,
+        oldScreenSpaceBottom;
+    oldScreenSpaceLeft   = oldX1       - oldScreenX1;
+    oldScreenSpaceRight  = oldScreenX2 - oldX2;
+    oldScreenSpaceTop    = oldY1       - oldScreenY1;
+    oldScreenSpaceBottom = oldScreenY2 - oldY2;
+
+    MSG(("moveToScreen:  %+5d,%+5d ; %+5d,%+5d",
+        oldScreenSpaceLeft,
+        oldScreenSpaceRight,
+        oldScreenSpaceTop,
+        oldScreenSpaceBottom));
+
+    double horizRatio, vertRatio;
+    horizRatio = (oldScreenSpaceLeft + oldScreenSpaceRight)
+                 ? (double)oldScreenSpaceLeft
+                   / (oldScreenSpaceLeft + oldScreenSpaceRight)
+                 : .5;
+    vertRatio  = (oldScreenSpaceTop  + oldScreenSpaceBottom)
+                 ? (double)oldScreenSpaceTop
+                    / (oldScreenSpaceTop  + oldScreenSpaceBottom)
+                 : .5;
+
+    MSG(("moveToScreen:        %+5.2f ;       %+5.2f", horizRatio, vertRatio));
+
+    int newScreenHorizSpace, newScreenVertSpace;
+    newScreenHorizSpace = (newScreenX2 - newScreenX1) - (oldX2 - oldX1);
+    newScreenVertSpace  = (newScreenY2 - newScreenY1) - (oldY2 - oldY1);
+
+    MSG(("moveToScreen:        %+5d ;       %+5d", newScreenHorizSpace, newScreenVertSpace));
+
+    int newScreenSpaceLeft, newScreenSpaceTop;
+    newScreenSpaceLeft = (int)(newScreenHorizSpace * horizRatio);
+    newScreenSpaceTop  = (int)(newScreenVertSpace  * vertRatio);
+
+    MSG(("moveToScreen:  %+5d,%+5d ; %+5d,%+5d",
+        newScreenSpaceLeft,
+        newScreenHorizSpace - newScreenSpaceLeft,
+        newScreenSpaceTop,
+        newScreenVertSpace  - newScreenSpaceTop));
+
+    int newX1, newX2, newY1, newY2;
+    newX1 = newScreenX1 + newScreenSpaceLeft;
+    newY1 = newScreenY1 + newScreenSpaceTop;
+
+    /* re-add remembered border{X,Y} */
+    /* this should not work for (borderLeft && borderRight) or
+       (borderTop && borderBottom) */
+    if (borderLeft) {
+        newX1 -= borderX();
+        oldX1 -= borderX();
+    }
+    if (borderRight) {
+        newX1 += borderX();
+        oldX1 += borderX();
+    }
+    if (borderTop) {
+        newY1 -= borderY();
+        oldY1 -= borderY();
+    }
+    if (borderBottom) {
+        newY1 += borderY();
+        oldY1 += borderY();
+    }
+
+    newX2 = newX1 + (oldX2 - oldX1);
+    newY2 = newY1 + (oldY2 - oldY1);
+
+    MSG(("moveToScreen: [%+5d,%+5d]x[%+5d,%+5d]\n", newX1, newX2, newY1, newY2));
+    setCurrentPositionOuter(newX1, newY1);
+
+    setState(fOldState, fOldState);
+}
+
 void YFrameWindow::wmArrange(int tcb, int lcr) {
     int mx, my, Mx, My, newX = 0, newY = 0;
 
diff --git a/src/wmframe.h b/src/wmframe.h
index bfa3b28..f2a39fa 100644
--- a/src/wmframe.h
+++ b/src/wmframe.h
@@ -436,6 +436,13 @@ public:
 
     int getScreen();
 
+    /*enum {
+        primaryScreen = -1,
+        nextScreen    = -2,
+        prevScreen    = -3
+    }*/
+    void moveToScreen(int newScreen = -1);
+
     long getOldLayer() { return fOldLayer; }
     void saveOldLayer() { fOldLayer = fWinActiveLayer; }
 
diff --git a/src/wmmgr.cc b/src/wmmgr.cc
index 50e7bfa..5c5a8c7 100644
--- a/src/wmmgr.cc
+++ b/src/wmmgr.cc
@@ -1899,6 +1899,47 @@ void YWindowManager::getWorkArea(const YFrameWindow *frame,
     }
 }
 
+void YWindowManager::getWorkArea(int *mx, int *my, int *Mx, int *My, int xiscreen, int ws) const
+{
+    bool whole = false;
+
+    if (ws == -1)
+        ws = activeWorkspace();
+
+    if (ws < 0 || ws >= fWorkAreaCount)
+        whole = true;
+
+    if (whole) {
+        *mx = 0;
+        *my = 0;
+        *Mx = width();
+        *My = height();
+    } else {
+
+/// TODO #warning "rewrite workarea determine code (per workspace)"
+#if 1
+        *mx = fWorkArea[ws].fMinX;
+        *my = fWorkArea[ws].fMinY;
+        *Mx = fWorkArea[ws].fMaxX;
+        *My = fWorkArea[ws].fMaxY;
+#endif
+    }
+
+    if (xiscreen != -1) {
+        int dx, dy, dw, dh;
+        manager->getScreenGeometry(&dx, &dy, &dw, &dh, xiscreen);
+
+        if (*mx < dx)
+            *mx = dx;
+        if (*my < dy)
+            *my = dy;
+        if (*Mx > dx + dw)
+            *Mx = dx + dw;
+        if (*My > dy + dh)
+            *My = dy + dh;
+    }
+}
+
 void YWindowManager::getWorkAreaSize(const YFrameWindow *frame, int *Mw,int *Mh) {
     int mx, my, Mx, My;
     manager->getWorkArea(frame, &mx, &my, &Mx, &My);
diff --git a/src/wmmgr.h b/src/wmmgr.h
index 5bc8060..4067f4c 100644
--- a/src/wmmgr.h
+++ b/src/wmmgr.h
@@ -94,6 +94,7 @@ public:
 
     void getWorkArea(const YFrameWindow *frame, int *mx, int *my, int *Mx, int *My, int xiscreen = -1) const;
     void getWorkAreaSize(const YFrameWindow *frame, int *Mw,int *Mh);
+    void getWorkArea(int *mx, int *my, int *Mx, int *My, int xiscreen, int ws = -1) const;
 
     int calcCoverage(bool down, YFrameWindow *frame, int x, int y, int w, int h);
     void tryCover(bool down, YFrameWindow *frame, int x, int y, int w, int h,
diff --git a/src/ywindow.cc b/src/ywindow.cc
index 82ed4a7..ca96f9f 100644
--- a/src/ywindow.cc
+++ b/src/ywindow.cc
@@ -1963,3 +1963,48 @@ int YDesktop::getScreenForRect(int x, int y, int width, int height) {
     return 0;
 #endif
 }
+
+int YDesktop::verifyScreen(int xiscreen, int fallback) {
+    if (fallback == -1)
+        fallback = xineramaPrimaryScreen;
+#ifdef XINERAMA
+    for (int s = 0; s < xiHeads; s++) {
+        if (xiInfo[s].screen_number == xiscreen) {
+            return xiscreen;
+        }
+    }
+#endif
+    return fallback;
+}
+
+int YDesktop::getNextScreen(int xiscreen) {
+#ifdef XINERAMA
+    if (xiscreen == -1)
+        xiscreen = xineramaPrimaryScreen;
+    for (int s = 0; s < xiHeads; s++) {
+        if (xiInfo[s].screen_number == xiscreen) {
+            s++;
+            if (s == xiHeads)
+                s = 0;
+            return xiInfo[s].screen_number;
+        }
+    }
+#endif
+    return xineramaPrimaryScreen;
+}
+
+int YDesktop::getPrevScreen(int xiscreen) {
+#ifdef XINERAMA
+    if (xiscreen == -1)
+        xiscreen = xineramaPrimaryScreen;
+    for (int s = 0; s < xiHeads; s++) {
+        if (xiInfo[s].screen_number == xiscreen) {
+            if (s == 0)
+                s = xiHeads;
+            s--;
+            return xiInfo[s].screen_number;
+        }
+    }
+#endif
+    return xineramaPrimaryScreen;
+}
diff --git a/src/ywindow.h b/src/ywindow.h
index 7441624..7818408 100644
--- a/src/ywindow.h
+++ b/src/ywindow.h
@@ -288,6 +288,9 @@ public:
                            int *width, int *height,
                            int screen_no = -1);
     int getScreenForRect(int x, int y, int width, int height);
+    int verifyScreen(int xiscreen, int fallback = -1);
+    int getNextScreen(int xiscreen = -1);
+    int getPrevScreen(int xiscreen = -1);
 
     virtual void grabKeys() {}
 
-- 
tg: (b1df5f6..) bw/move-to-screen (depends on: icewm-1.2)

 	  	 
