foo-wm

(Archived) Experimental Zooming IPC-based WM
git clone http://milesalan.com/git/foo-wm
Log | Files | Refs | Mirror | README | LICENSE

tree.c (13450B)


      1 #include <X11/Xlib.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 #include <math.h>
      6 #include "atoms.h"
      7 #include "foo-wm.h"
      8 #include "tree.h"
      9 #include "lookup.h"
     10 #include "util.h"
     11 #include "window.h"
     12 
     13 /* --------------------------------------------------------------------------
     14  * Bool Returns 
     15  * -------------------------------------------------------------------------- */
     16 Bool areBrothers(Node * nodeA, Node * nodeB) {
     17   if ((!nodeA || !nodeB) || nodeA -> parent != nodeB -> parent) return False;
     18 
     19   Bool hasA, hasB;
     20   Node *n = NULL;
     21   for (n = nodeA -> parent -> child; n; n = n -> next) {
     22     if (n == nodeA) hasA = True;
     23     if (n == nodeB) hasB = True;
     24   }
     25 
     26   if (hasA && hasB) return True;
     27   else return False;
     28 }
     29 
     30 Bool isClient(Node * node) { 
     31   /* Is the node a client? */
     32   if (node && (node -> window != (Window) NULL)) return True;
     33   else return False;  
     34 }
     35 
     36 Bool isOnlyChild(Node * node) { 
     37   /* Is the node an only child */
     38   if (node && (node -> next || node -> previous)) return False;
     39   else return True;
     40 }
     41 
     42 Bool nodeIsParentOf(Node * nodeA, Node * nodeB) {
     43   /* Searches nodeA for an occurance of nodeB
     44    * if successful, return true */
     45   if (nodeA == nodeB) return True;
     46 
     47   Node *n = NULL;
     48   for (n = nodeA -> child; n; n = n -> next) {
     49     if (nodeIsParentOf(n, nodeB))
     50       return True;
     51   }
     52 
     53   return False;
     54 }
     55 
     56 Bool unfocusNode(Node * n, Bool focusPath) {
     57   /* Unfocuses the currently focused node, called only by focusNode 
     58    * Returns Bool if an update of the view is needed
     59    * Dangerous if called alone */
     60   if (!n) return False;
     61 
     62   Bool setView = (n == viewNode) ? True : False;
     63   fprintf(stderr, "Yo i be unfocusing %p\n", n);
     64 
     65   //Unfocusing Code for previous focusedNode
     66   if (isClient(n)) {
     67 
     68     //This should only apply to the most innard focus of focusedNode, follow ptrs
     69     if (focusPath)
     70       XGrabButton(display, AnyButton, AnyModifier,
     71           n -> window, True, ButtonPressMask | ButtonReleaseMask,
     72           GrabModeAsync, GrabModeAsync, None, None);
     73 
     74   } else {
     75     //Recursive loop on children to set 
     76 
     77     Node *c;
     78     for (c = n -> child; c; c = c -> next)
     79       unfocusNode(c, c -> parent -> focus == c ? True : False);
     80   }
     81 
     82   return setView;
     83 }
     84 
     85 /* --------------------------------------------------------------------------
     86  * Long Returns 
     87  * -------------------------------------------------------------------------- */
     88 long getBorderColor(Node * node, Bool focusPath) {
     89   if (focusPath) {
     90     if (focusedNode == node)
     91       return activeFocusedColor;
     92     else
     93       return node -> parent -> focus == node ? 
     94         inactiveFocusedColor : activeUnfocusedColor;
     95 
     96   } else {
     97     return node -> parent -> focus == node ? 
     98       inactiveFocusedColor: inactiveUnfocusedColor;
     99   }
    100 }
    101 
    102 
    103 /* --------------------------------------------------------------------------
    104  * Node Returns 
    105  * -------------------------------------------------------------------------- */
    106 Node * getBrother(Node * node, int delta) {
    107   if (!node) return NULL;
    108 
    109   while (delta > 0) {
    110     if (node -> next)
    111       node = node -> next;
    112     else if (node -> parent && node -> parent -> child)
    113       node = node -> parent -> child;
    114     delta--;
    115   }
    116 
    117   while (delta < 0) {
    118     if (node -> previous) {
    119       node = node -> previous;
    120     } else if (node -> parent && node -> parent -> child) {
    121       node = node -> parent -> child;
    122       while (node -> next)
    123         node = node -> next;
    124     } else { fprintf(stderr, "Not a good situation\n"); }
    125 
    126     delta++;
    127   }
    128 
    129   return node;
    130 }
    131 
    132 /* Gets the next brother client to node, in given direction 
    133  * [Container] - [Client X] - [Container] - [Container] - [Client Y]
    134  * Given Client X, function would loop until hitting Client Y
    135  * */
    136 Node * getBrotherClient(Node * node, int direction) {
    137   Node *pNode = node;
    138   Node *nNode = node;
    139 
    140   while (pNode -> previous || nNode -> next) {
    141     if (pNode -> previous ) pNode = pNode -> previous;
    142     if (nNode -> next     ) nNode = nNode -> next;
    143     switch (direction) {
    144       case 0:
    145         if (isClient(pNode) && pNode != node) return pNode;
    146         if (isClient(nNode) && nNode != node) return nNode;
    147         break;
    148       case 1:
    149         if (isClient(nNode) && nNode != node) return nNode;
    150         if (isClient(pNode) && pNode != node) return pNode;
    151         break;
    152     }
    153   }
    154   return NULL;
    155 }
    156 
    157 
    158 Node * getClosestClient(Node * node) {
    159   Node * returnNode = NULL;
    160   Node * currentNode = node;
    161 
    162   /* Calls getBrotherClient going up the tree until a client is found */
    163   while (!returnNode) {
    164     returnNode = getBrotherClient(currentNode, 1);
    165     if (!returnNode) {
    166       if (currentNode -> parent) currentNode = currentNode -> parent;
    167       else                               return NULL;
    168     } else {  //We found a client 
    169       return returnNode; 
    170     }
    171   }
    172   return NULL;
    173 }
    174 
    175 
    176 
    177 /* --------------------------------------------------------------------------
    178  * Void Returns 
    179  * -------------------------------------------------------------------------- */
    180 void brotherNode(Node *node, Node * brother, int position) {
    181   if (!node || !brother) return;
    182   node -> parent = brother -> parent;
    183 
    184   if (position == 0) {
    185     node -> next = brother;
    186     if (!brother -> previous) { //Pop in the front
    187       node -> parent -> child = node;
    188     } else {
    189       //Shift previous pointer
    190       node -> previous = brother -> previous;
    191       if (node -> previous) node -> previous -> next = node;
    192     }
    193     brother -> previous = node;
    194   } else if (position == 1) {
    195     node -> previous = brother;
    196     node -> next = brother -> next;
    197     if (node -> next) node -> next -> previous = node;
    198     brother -> next = node;
    199   }
    200 }
    201 
    202 
    203 void destroyNode(Node * n) {
    204   if (!n) return;
    205 
    206   //Recursvily unmap up any lone parents
    207   if (n -> parent && n -> parent != viewNode && isOnlyChild(n) && 
    208       n -> parent -> child == n && n -> parent -> parent) {
    209     destroyNode(n -> parent);
    210     return;
    211   }
    212 
    213   //Unparent the node
    214   unparentNode(n);
    215   fprintf(stderr, "Made it here");
    216 
    217   if (n == focusedNode) focusedNode = NULL;
    218   fprintf(stderr, "n is %p", n);
    219 
    220   //Recursivly unmap down all children of the node
    221   if (isClient(n)) {
    222     removeLookupEntry(&n -> window);
    223 
    224     //Send ICCCM Delete Atom
    225     sendDeleteWindow(&n -> window);
    226 
    227 
    228     XDestroyWindow(display, n -> window);
    229     free(n);
    230   } else if (n) {
    231     Node *destroy = n -> child; Node *next = NULL;
    232     do {
    233       if (destroy) {
    234         next = destroy -> next;
    235         destroyNode(destroy);
    236       } else { next = NULL; }
    237     } while (next);
    238 
    239     //if (n -> parent && n -> parent -> focus == n) n -> parent -> child = NULL;
    240     //free(n);
    241   }
    242 
    243 }
    244 
    245 
    246 //This should focus OR select
    247 void focusNode(Node * n, XEvent * event, Bool setFocused, Bool focusPath) {
    248   if (!n || n == focusedNode) return;
    249   fprintf(stderr, "Focusing %p", n);
    250 
    251   Node *oldFocus = focusedNode;
    252 
    253 
    254   /* Focus path and set focus --> Update the focus ptr of parent */
    255   if (focusPath && setFocused) {
    256     fprintf(stderr, "\n\nNode %p, is in the focus path\n\n", n);
    257     unfocusNode(focusedNode, True);
    258     if (setFocused && n -> parent)   n -> parent -> focus = n;
    259   }
    260 
    261   /* Setting focus */
    262   if (setFocused)  {
    263     focusedNode = n;
    264 
    265     if (oldFocus && nodeIsParentOf(viewNode, oldFocus))
    266       rePlaceNode(oldFocus); 
    267     if (oldFocus == viewNode && nodeIsParentOf(focusedNode, viewNode))
    268       viewNode = n;
    269     if (areBrothers(oldFocus, focusedNode)) 
    270       placeNode(focusedNode, oldFocus -> x, oldFocus -> y, oldFocus -> width, oldFocus -> height);
    271 
    272     placeNode(viewNode, rootX, rootY, rootWidth, rootHeight);
    273 
    274   }
    275 
    276   // Are we at the bottom level 
    277   if (isClient(n)) {
    278     if (focusPath) {
    279       XSetInputFocus(display, n -> window, RevertToParent, CurrentTime);  
    280       XUngrabButton(display, AnyButton, AnyModifier, n ->window);
    281       XRaiseWindow(display, n -> window);
    282 
    283       if (event) {
    284         // Set the Input focus, and ungrab the window (no longer point to click)
    285         XSendEvent(display, n -> window, True, ButtonPressMask, event);
    286       } else {
    287         centerPointer(&n -> window);
    288       }
    289     }
    290 
    291   } else {
    292     /* Focus on container -- recur down focus path */
    293     Node *i = NULL;
    294     for (i = n -> child; i; i = i -> next) {
    295       focusNode(i, NULL, False, 
    296           i -> parent -> focus == i ? True : False);
    297     }
    298   }
    299 }
    300 
    301 
    302 void parentNode(Node *node, Node *parent) {
    303   fprintf(stderr, "Pareting node %p into parent %p\n", node, parent);
    304   if (!node || !parent) return;  //Cant add to NULL
    305 
    306   unparentNode(node); //Unparent then set the parent to new parent
    307   node -> parent = parent;
    308   if (!parent -> focus) parent -> focus = node;
    309 
    310   //Find last in children of parent, add to end
    311   if (parent -> child) {
    312     Node *n = parent -> child;
    313     while (n -> next) n = n -> next;
    314     node -> previous = n;
    315     n -> next = node;
    316   } else {
    317     parent -> child = node;
    318   }
    319 }
    320 
    321 void placeNode(Node * node, int x, int y, int width, int height) {
    322   if (!node) return;
    323   node -> x = x; node -> y = y; node -> width = width; node -> height = height;
    324   fprintf(stderr, "Place Node XY:[%d, %d], WH:[%d, %d]\n", x, y, width, height);
    325 
    326   if (isClient(node)) {
    327     fprintf(stderr,"Rendering window\n");
    328     XMapWindow(display, node -> window);
    329     XRaiseWindow(display, node -> window);
    330     XMoveResizeWindow(display, node -> window, 
    331         (x < 0) ? 0 : x, (y < 0) ? 0 : y, 
    332         (width -  (border * 2)) > 0 ? (width - border * 2) : 1, 
    333         (height - (border * 2)) > 0 ? (height- border * 2) : 1);
    334     XSetWindowBorderWidth(display, node -> window, border);
    335 
    336     Node *b = node; Bool inFocusPath = False;
    337 
    338     if (b == focusedNode) {
    339       inFocusPath = True;
    340     } else {
    341       do {  //Figure out if were in the focus path
    342         b = b -> parent;
    343         if (b == focusedNode) inFocusPath = True;
    344       } while (b -> parent);
    345     }
    346 
    347     XSetWindowBorder(display, node -> window, getBorderColor(node, inFocusPath));
    348 
    349   } else {
    350     //Count up children prior to loop
    351     int children = 0; int i = 0; Node *a = NULL;
    352     if (!node -> child) return;
    353     for (a = node -> child; a; a = a -> next) children++;
    354 
    355     /* Determine the number of rows and cols */
    356     int rows; int cols;
    357     switch (node -> layout) {
    358       /* Emulate a grid  regardless */
    359       case VERTICAL  : cols = children; rows = 1; break;
    360       case HORIZONTAL: cols = 1; rows = children; break;
    361       case GRID      : gridDimensions(children, &rows, &cols); break;
    362       case MAX       : cols = 1; rows = 1; break;
    363     }
    364 
    365     Bool callPlace;
    366     int pad;
    367     for (a = node -> child; a; a = a -> next, i++) {
    368 
    369       if (node -> layout == FLOAT) {
    370         placeNode(a, a -> x + 10, a -> y + 10 , a -> width - 20, a -> height - 20);
    371 
    372       } else { /* Rendering based on a grid style */
    373 
    374         pad = isClient(a) ? clientPadding : containerPadding;
    375         callPlace = True;
    376         if (node -> layout == MAX) {
    377           if (a -> parent -> focus == a) i = 0; 
    378           else callPlace = False;
    379         }
    380 
    381         a -> x = x + (i % cols) * (width/cols) + pad;
    382         a -> y = y + ((int)(i / cols)) * (height/rows) + pad;
    383         a -> width = width / cols - (pad * 2);
    384         a -> height = height / rows - (pad * 2);
    385 
    386         if (callPlace) {  
    387 
    388           if (node -> layout == GRID) { /* Must account for prime case */
    389             if (children == 2)      a -> height = height - (pad * 2);
    390             if (i + 1 == children)  a -> width = x + width - a -> x - (pad * 2);
    391           }
    392           rePlaceNode(a);
    393         } else {
    394           fprintf(stderr, "Going to call unmap on %p\n", a);
    395           unmapNode(a);
    396         }
    397 
    398       }
    399     }
    400   }
    401 }
    402 
    403 void rePlaceNode(Node * node) {
    404   placeNode(node, node -> x, node -> y, node -> width, node -> height);
    405 }
    406 
    407 /* Swaps nodes within the same container of the tree 
    408  * [ NULL <- A <-> B <-> C <-> D -> NULL ] */
    409 void swapNodes(Node * a, Node * b) {
    410   if (!a || !b || a == b) return;
    411 
    412   /* Update Parent / Parent -> Child Pointer */
    413   Node *temp = NULL;
    414   if (a -> parent -> child == a)      a -> parent -> child = b;
    415   else if (b -> parent -> child == b) b -> parent -> child = a;
    416 
    417   /* Update Previous Pointer */
    418   temp = a -> previous; a -> previous = b -> previous;
    419   if (a -> previous) a -> previous -> next = a;
    420   b -> previous = temp;
    421   if (b -> previous) b -> previous -> next = b;
    422 
    423   /* Update Next Pointer */
    424   temp = a -> next; a -> next = b -> next;
    425   if (a -> next) a -> next -> previous = a;
    426   b -> next = temp;
    427   if (b -> next) b -> next -> previous = b;
    428 
    429   /* Replace node */
    430   placeNode(viewNode, viewNode -> x, viewNode -> y,
    431       viewNode -> width, viewNode -> height);
    432 }
    433 
    434 
    435 void unmapNode(Node * node) {
    436   if (isClient(node)) {
    437     XUnmapWindow(display, node -> window);
    438   } else {
    439     Node *n = NULL;
    440     for (n = node -> child; n; n = n -> next)
    441       unmapNode(n);
    442   }
    443 }
    444 
    445 
    446 void unparentNode(Node *node) {
    447   if (!(node && node -> parent)) return;
    448 
    449   fprintf(stderr, "Unparent called\n");
    450   //Move parent's child pointer if were it....
    451   if (node -> parent -> child == node)
    452     node -> parent -> child = node -> next;
    453   if (node -> parent -> focus == node)
    454     node -> parent -> focus = node -> parent -> child;
    455 
    456   //Move the next and previous pointers to cut out the node
    457   if (node -> next)     node -> next -> previous = node -> previous;
    458   if (node -> previous) node -> previous -> next = node -> next;
    459 
    460   //Set our parent to NULL
    461   Node * oldParent = node -> parent;
    462   node -> parent = NULL; node -> next = NULL; node -> previous = NULL;
    463   if (!oldParent -> child)
    464     destroyNode(oldParent);
    465 }