kwo pushed a commit to branch master.

http://git.enlightenment.org/e16/e16.git/commit/?id=85912e39e2f8a85496ffe678587a4e505ea0d0a0

commit 85912e39e2f8a85496ffe678587a4e505ea0d0a0
Author: Kim Woelders <[email protected]>
Date:   Fri Jan 28 11:28:31 2022 +0100

    New feature - Making windows stick on specific desks/areas
---
 src/desktops.c | 53 +++++++++++++++++++++++++++++++-
 src/ewin-ops.c | 10 ++++++-
 src/ewin-ops.h |  3 +-
 src/ewins.c    | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/ewins.h    | 26 ++++++++++++++--
 src/ipc.c      | 52 ++++++++++++++++++++++++++++++--
 src/snaps.c    | 52 ++++++++++++++++++++++++++++----
 7 files changed, 276 insertions(+), 15 deletions(-)

diff --git a/src/desktops.c b/src/desktops.c
index 1fdc9597..d091e8ad 100644
--- a/src/desktops.c
+++ b/src/desktops.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2021 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -53,6 +53,13 @@
 #include "xprop.h"
 #include "xwin.h"
 
+#define DEBUG_DESKS 0
+#if DEBUG_DESKS
+#define Dprintf(fmt...) if(EDebug(EDBUG_TYPE_DESKS))Eprintf(fmt)
+#else
+#define Dprintf(fmt...)
+#endif
+
 #define DESK_EVENT_MASK1 \
   (ButtonPressMask | ButtonReleaseMask)
 #define DESK_EVENT_MASK2 \
@@ -1195,6 +1202,28 @@ DeskSwitchDone(void)
    FocusNewDesk();
 }
 
+static int
+_doDeskGotoEndDeferred(void *data __UNUSED__)
+{
+   Dprintf("%s\n", __func__);
+
+   /* The "deferring" is an attempt to delay the pinned window moving
+    * to after a potential area move following a desk switch.
+    * Otherwise we will move windows that are pinned to the target desktop
+    * initial area but not on the target area. */
+   EwinsMovePinnedToDesk(desks.current);
+
+   return 0;
+}
+
+static void
+_DeskGotoEndDeferred(void)
+{
+   Dprintf("%s\n", __func__);
+
+   TIMER_ADD_NP(0, _doDeskGotoEndDeferred, NULL);
+}
+
 static void
 _DeskGotoStart(Desk * dsk)
 {
@@ -1217,6 +1246,8 @@ _DeskGotoEnd(Desk * dsk)
 
    if (EDebug(EDBUG_TYPE_DESKS))
       Eprintf("%s: %d\n", __func__, dsk->num);
+
+   _DeskGotoEndDeferred();
 }
 
 static int
@@ -1732,6 +1763,7 @@ typedef struct {
    EWin              **ewins_slide;
    int                 n_ewins_desk, n_ewins_slide;
    int                 slide_dx, slide_dy;
+   int                 ax, ay;
 } slide_area_data_t;
 
 static void
@@ -1747,12 +1779,26 @@ _DeskCurrentGotoAreaEnd(slide_area_data_t * sad)
    dx = sad->slide_dx;
    dy = sad->slide_dy;
 
+   if (EDebug(EDBUG_TYPE_DESKS))
+      Eprintf("%s: %d,%d\n", __func__, sad->ax, sad->ay);
+
    /* move all windows to their final positions */
    for (i = 0; i < num; i++)
      {
        ewin = lst[i];
        if (EwinIsTransientChild(ewin))
           continue;
+
+       if (EwinIsPinnedMisplaced(ewin, DesksGetCurrentNum(), sad->ax, sad->ay))
+         {
+            EwinMoveToDesktopAtNocheck(ewin, DesksGetCurrent(),
+                                       ewin->vx -
+                                       ewin->area_x * WinGetW(VROOT),
+                                       ewin->vy -
+                                       ewin->area_y * WinGetH(VROOT));
+            continue;
+         }
+
        if (EoGetDesk(ewin) != DesksGetCurrent() && !EoIsFloating(ewin))
           continue;
 
@@ -1844,6 +1890,8 @@ DeskCurrentGotoArea(int ax, int ay)
    sad->n_ewins_slide = 0;
    sad->slide_dx = dx;
    sad->slide_dy = dy;
+   sad->ax = ax;
+   sad->ay = ay;
 
    if (Conf.desks.slidein && Conf.desks.slidespeed > 10)
      {
@@ -1862,6 +1910,9 @@ DeskCurrentGotoArea(int ax, int ay)
             if (EoIsFloating(ewin) && Conf.movres.mode_move == MR_OPAQUE)
                continue;
 
+            if (EwinIsPinnedMisplaced(ewin, EoGetDeskNum(ewin), ax, ay))
+               continue;
+
             wnum++;
             wl = EREALLOC(EWin *, wl, wnum);
             wl[wnum - 1] = ewin;
diff --git a/src/ewin-ops.c b/src/ewin-ops.c
index 4c67abdf..a5fdff72 100644
--- a/src/ewin-ops.c
+++ b/src/ewin-ops.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2021 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -57,6 +57,7 @@ static const WinOp  winops[] = {
    {"shadow", 0, 1, 1, EWIN_OP_SHADOW},        /* Place before "shade" */
    {"shade", 2, 1, 1, EWIN_OP_SHADE},
    {"stick", 2, 1, 1, EWIN_OP_STICK},
+   {"pin", 0, 1, 1, EWIN_OP_PIN},
    {"focus", 2, 1, 0, EWIN_OP_FOCUS},
 
    {"desk", 2, 1, 1, EWIN_OP_DESK},
@@ -476,6 +477,13 @@ EwinMoveToDesktopAt(EWin * ewin, Desk * dsk, int x, int y)
    doEwinMoveResize(ewin, dsk, x, y, 0, 0, MRF_DESK | MRF_MOVE);
 }
 
+void
+EwinMoveToDesktopAtNocheck(EWin * ewin, Desk * dsk, int x, int y)
+{
+   doEwinMoveResize(ewin, dsk, x, y, 0, 0,
+                   MRF_DESK | MRF_MOVE | MRF_NOCHECK_ONSCREEN);
+}
+
 void
 EwinOpMove(EWin * ewin, int source, int x, int y)
 {
diff --git a/src/ewin-ops.h b/src/ewin-ops.h
index 09cf8f88..e8d85c39 100644
--- a/src/ewin-ops.h
+++ b/src/ewin-ops.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2011 Kim Woelders
+ * Copyright (C) 2005-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -36,6 +36,7 @@ typedef enum {
    EWIN_OP_SHADE,
    EWIN_OP_STICK,
    EWIN_OP_FOCUS,
+   EWIN_OP_PIN,
 
    EWIN_OP_DESK,
    EWIN_OP_AREA,
diff --git a/src/ewins.c b/src/ewins.c
index 30065e89..e6da7a65 100644
--- a/src/ewins.c
+++ b/src/ewins.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2021 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -1920,6 +1920,78 @@ EwinWarpTo(EWin * ewin, int force)
    Mode.mouse_over_ewin = ewin;
 }
 
+int
+EwinIsPinnedMisplaced(EWin * ewin, int desk, int ax, int ay)
+{
+   return ((int)EoGetDeskNum(ewin) != desk ||
+          ewin->area_x != ax || ewin->area_y != ay) &&
+      EwinIsPinnedOn(ewin, desk, ax, ay) >= 0;
+}
+
+int
+EwinIsPinnedOn(EWin * ewin, int desk, int ax, int ay)
+{
+   unsigned int        i;
+   DeskArea           *dxy = ewin->pinned;
+
+   for (i = 0; i < ewin->num_pinned; i++, dxy++)
+     {
+       if (dxy->desk == desk && dxy->ax == ax && dxy->ay == ay)
+          return i;
+     }
+
+   return -1;
+}
+
+void
+EwinPinOn(EWin * ewin, int on, int desk, int ax, int ay)
+{
+   int                 ix;
+   unsigned int        num;
+
+   if (on == -2)
+     {
+       /* Cleaar all */
+       EFREE_NULL(ewin->pinned);
+       ewin->num_pinned = 0;
+       goto done;
+     }
+
+   if (desk < 0 || ax < 0 || ay < 0)
+      return;
+
+   ix = EwinIsPinnedOn(ewin, desk, ax, ay);
+
+   if (on < 0)
+      on = ix < 0;             /* Toggle */
+
+   if (on)
+     {
+       if (ix >= 0)
+          return;              /* Already set */
+
+       num = ewin->num_pinned++;
+       ewin->pinned = EREALLOC(DeskArea, ewin->pinned, ewin->num_pinned);
+       ewin->pinned[num].all = 0;
+       ewin->pinned[num].desk = desk;
+       ewin->pinned[num].ax = ax;
+       ewin->pinned[num].ay = ay;
+     }
+   else
+     {
+       if (ix < 0)
+          return;              /* Not set */
+
+       ewin->num_pinned--;
+       num = ewin->num_pinned - ix;    /* Items to move */
+       if (num != 0)
+          memmove(ewin->pinned + ix, ewin->pinned + 1, num * sizeof(DeskArea));
+     }
+
+ done:
+   SnapshotEwinUpdate(ewin, SNAP_USE_STICKY);
+}
+
 typedef union {
    unsigned int        all;
    struct {
@@ -2228,6 +2300,27 @@ EwinsMoveStickyToDesk(Desk * dsk)
      }
 }
 
+void
+EwinsMovePinnedToDesk(Desk * dsk)
+{
+   EWin               *const *lst, *ewin;
+   int                 i, num, ax, ay;
+
+   DeskGetArea(dsk, &ax, &ay);
+
+   lst = EwinListStackGet(&num);
+   for (i = 0; i < num; i++)
+     {
+       ewin = lst[num - 1 - i];
+       if (!EwinIsPinnedMisplaced(ewin, dsk->num, ax, ay))
+          continue;
+
+       EwinMoveToDesktopAtNocheck(ewin, dsk,
+                                  ewin->vx - ewin->area_x * WinGetW(VROOT),
+                                  ewin->vy - ewin->area_y * WinGetH(VROOT));
+     }
+}
+
 void
 EwinsManage(void)
 {
diff --git a/src/ewins.h b/src/ewins.h
index 8ec49d61..94a2ef29 100644
--- a/src/ewins.h
+++ b/src/ewins.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2021 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -64,6 +64,15 @@ typedef struct {
    void                (*Close)(EWin * ewin);
 } EWinOps;
 
+typedef union {
+   unsigned int        all;
+   struct {
+      unsigned char       rsvd;
+      unsigned char       desk;
+      unsigned char       ax, ay;
+   };
+} DeskArea;
+
 struct _ewin {
    EObj                o;
    char                type;
@@ -250,7 +259,12 @@ struct _ewin {
 
    int                 num_groups;
    Group             **groups;
+
    int                 area_x, area_y;
+
+   unsigned int        num_pinned;
+   DeskArea           *pinned;
+
    char               *session_id;
    PmapMask            mini_pmm;
 
@@ -410,7 +424,13 @@ EWin              **EwinListTransientFor(const EWin * 
ewin, int *num);
 void                EwinsManage(void);
 void                EwinsSetFree(void);
 void                EwinsShowDesktop(int on);
-void                EwinsMoveStickyToDesk(Desk * d);
+void                EwinsMoveStickyToDesk(Desk * dsk);
+void                EwinsMovePinnedToDesk(Desk * dsk);
+
+void                EwinPinOn(EWin * ewin, int on, int desk, int ax, int ay);
+int                 EwinIsPinnedOn(EWin * ewin, int desk, int ax, int ay);
+int                 EwinIsPinnedMisplaced(EWin * ewin,
+                                         int desk, int ax, int ay);
 
 /* ewin-ops.c */
 /* Move/resize flags */
@@ -425,6 +445,8 @@ void                EwinMoveResizeWithGravity(EWin * ewin, 
int x, int y, int w,
                                              int h, int grav);
 void                EwinMoveToDesktop(EWin * ewin, Desk * d);
 void                EwinMoveToDesktopAt(EWin * ewin, Desk * d, int x, int y);
+void                EwinMoveToDesktopAtNocheck(EWin * ewin, Desk * dsk,
+                                              int x, int y);
 void                EwinIconify(EWin * ewin);
 void                EwinAlone(EWin * ewin);
 void                EwinDeIconify(EWin * ewin);
diff --git a/src/ipc.c b/src/ipc.c
index 029bf558..b8ef4825 100644
--- a/src/ipc.c
+++ b/src/ipc.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2021 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -427,9 +427,9 @@ static void
 IpcWinop(const WinOp * wop, EWin * ewin, const char *prm)
 {
    char                param1[128], param2[128];
-   unsigned int        val;
+   unsigned int        i, val;
    char                on;
-   int                 a, b;
+   int                 a, b, d;
 
    param1[0] = param2[0] = '\0';
    sscanf(prm, "%127s %127s", param1, param2);
@@ -508,6 +508,47 @@ IpcWinop(const WinOp * wop, EWin * ewin, const char *prm)
        EwinOpActivate(ewin, OPSRC_USER, 1);
        break;
 
+     case EWIN_OP_PIN:
+       if (!param1[0])
+         {
+            IpcPrintf("Error: no parameters supplied\n");
+            goto done;
+         }
+       else if (!strcmp(param1, "?"))
+         {
+            for (i = 0; i < ewin->num_pinned; i++)
+               IpcPrintf("%2d: %d,%d\n", ewin->pinned[i].desk,
+                         ewin->pinned[i].ax, ewin->pinned[i].ay);
+         }
+       else if (!strcmp(param1, "clear"))
+         {
+            EwinPinOn(ewin, -2, 0, 0, 0);
+         }
+       else
+         {
+            if (!strcmp(param1, "on"))
+               on = 1;
+            else if (!strcmp(param1, "off"))
+               on = 0;
+            else if (!strcmp(param1, "tgl"))
+               on = -1;
+            else
+               break;
+
+            if (param2[0] == '*')
+              {
+                 d = EoGetDeskNum(ewin);
+                 DeskGetArea(EoGetDesk(ewin), &a, &b);
+              }
+            else
+              {
+                 a = b = d = -1;
+                 sscanf(prm, "%*s %u %u %u", &d, &a, &b);
+              }
+            EwinPinOn(ewin, on, d, a, b);
+         }
+       break;
+
      case EWIN_OP_DESK:
        if (!param1[0])
          {
@@ -1546,6 +1587,7 @@ IPC_Compat(const char *params)
  */
 static void         IPC_Help(const char *params);
 
+/**INDENT-OFF**/
 static const IpcItem IPCArray[] = {
    {
     IPC_Help,
@@ -1606,6 +1648,9 @@ static const IpcItem IPCArray[] = {
     "  win_op <windowid> title <title>\n"
     "  win_op <windowid> <close/kill>\n"
     "  win_op <windowid> <focus/iconify/alone/shade/stick>\n"
+    "  win_op <windowid> pin <on/off/tgl> desk area_x area_y\n"
+    "                    pin ?\n"
+    "                    pin clear\n"
 #if USE_COMPOSITE
     "  win_op <windowid> <fade/shadow>\n"
 #endif
@@ -1706,6 +1751,7 @@ static const IpcItem IPCArray[] = {
     "  keys <string>\n"},
 #endif
 };
+/**INDENT-ON**/
 
 static int          ipc_item_count = 0;
 static const IpcItem **ipc_item_list = NULL;
diff --git a/src/snaps.c b/src/snaps.c
index a783bdec..c98fdcd9 100644
--- a/src/snaps.c
+++ b/src/snaps.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various 
contributors
- * Copyright (C) 2004-2020 Kim Woelders
+ * Copyright (C) 2004-2022 Kim Woelders
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to
@@ -21,6 +21,7 @@
  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
+#include <arpa/inet.h>
 #include "E.h"
 #include "borders.h"
 #include "desktops.h"
@@ -33,6 +34,7 @@
 #include "settings.h"
 #include "snaps.h"
 #include "timers.h"
+#include "util.h"
 #include "xwin.h"
 
 struct _snapshot {
@@ -57,6 +59,8 @@ struct _snapshot {
    int                 layer;
    char                shaded;
    char                sticky;
+   int                *pinned;
+   int                 num_pinned;
    unsigned int        flags[2];
    char               *cmd;
    int                *groups;
@@ -349,6 +353,10 @@ static void
 _SnapUpdateEwinSticky(Snapshot * sn, const EWin * ewin)
 {
    sn->sticky = EoIsSticky(ewin);
+   sn->num_pinned = ewin->num_pinned;
+   EFREE_NULL(sn->pinned);
+   if (sn->num_pinned)
+      sn->pinned = EMEMDUP(int, ewin->pinned, ewin->num_pinned);
 }
 
 static void
@@ -1118,7 +1126,15 @@ SnapshotsSaveReal(void)
       if (sn->use_flags & SNAP_USE_LAYER)
         fprintf(f, "LAYER: %i\n", sn->layer);
       if (sn->use_flags & SNAP_USE_STICKY)
-        fprintf(f, "STICKY: %i\n", sn->sticky);
+       {
+          fprintf(f, "STICKY: %i", sn->sticky);
+          if (sn->pinned)
+            {
+               for (i = 0; i < sn->num_pinned; i++)
+                  fprintf(f, " %06x", htonl(sn->pinned[i]));
+            }
+          fprintf(f, "\n");
+       }
       if (sn->use_flags & SNAP_USE_SHADED)
         fprintf(f, "SHADE: %i\n", sn->shaded);
       if (sn->use_flags & SNAP_USE_SKIP_LISTS)
@@ -1317,7 +1333,20 @@ _SnapshotsLoad(FILE * fs)
             else if (!strcmp(buf, "STICKY"))
               {
                  sn->use_flags |= SNAP_USE_STICKY;
-                 sn->sticky = atoi(s);
+                 a = b = 0;
+                 sscanf(s, "%d %n", &a, &b);
+                 sn->sticky = a;
+                 for (;;)
+                   {
+                      s += b;
+                      b = 0;
+                      sscanf(s, "%x %n", &a, &b);
+                      if (b <= 0)
+                         break;
+                      sn->num_pinned++;
+                      sn->pinned = EREALLOC(int, sn->pinned, sn->num_pinned);
+                      sn->pinned[sn->num_pinned - 1] = htonl(a);
+                   }
               }
             else if (!strcmp(buf, "SHADE"))
               {
@@ -1427,7 +1456,11 @@ SnapshotEwinApply(EWin * ewin)
         SNAP_USE_OPACITY;
 
    if (use_flags & SNAP_USE_STICKY)
-      EoSetSticky(ewin, sn->sticky);
+     {
+       EoSetSticky(ewin, sn->sticky);
+       ewin->num_pinned = sn->num_pinned;
+       ewin->pinned = EMEMDUP(DeskArea, sn->pinned, sn->num_pinned);
+     }
 
    if (use_flags & SNAP_USE_DESK)
       EoSetDesk(ewin, DeskGetValid(sn->desktop));
@@ -1452,8 +1485,15 @@ SnapshotEwinApply(EWin * ewin)
        if (!EoIsSticky(ewin))
          {
             DeskGetArea(EoGetDesk(ewin), &ax, &ay);
-            ewin->client.x += ((sn->area_x - ax) * WinGetW(VROOT));
-            ewin->client.y += ((sn->area_y - ay) * WinGetH(VROOT));
+            if (EwinIsPinnedOn(ewin, DesksGetCurrentNum(), ax, ay) >= 0)
+              {
+                 EoSetDesk(ewin, DesksGetCurrent());
+              }
+            else
+              {
+                 ewin->client.x += ((sn->area_x - ax) * WinGetW(VROOT));
+                 ewin->client.y += ((sn->area_y - ay) * WinGetH(VROOT));
+              }
          }
      }
 

-- 


Reply via email to