win_regions.c revision b18c2d1e
1/* 2 * WindowRegion handling 3 */ 4 5#include "ctwm.h" 6 7#include <stdlib.h> 8 9#include "list.h" 10#include "screen.h" 11#include "win_regions.h" 12#include "xparsegeometry.h" 13 14 15static void splitWindowRegionEntry(WindowEntry *we, 16 RegGravity grav1, RegGravity grav2, 17 int w, int h); 18static WindowEntry *findWindowEntry(WorkSpace *wl, 19 TwmWindow *tmp_win, WindowRegion **wrp); 20static WindowEntry *prevWindowEntry(WindowEntry *we, WindowRegion *wr); 21static void mergeWindowEntries(WindowEntry *old, WindowEntry *we); 22 23 24 25/* 26 * Backend for the parser when it hits WindowRegion 27 */ 28name_list ** 29AddWindowRegion(char *geom, RegGravity grav1, RegGravity grav2) 30{ 31 WindowRegion *wr; 32 int mask; 33 34 wr = malloc(sizeof(WindowRegion)); 35 wr->next = NULL; 36 37 if(!Scr->FirstWindowRegion) { 38 Scr->FirstWindowRegion = wr; 39 } 40 41 wr->entries = NULL; 42 wr->clientlist = NULL; 43 wr->grav1 = grav1; 44 wr->grav2 = grav2; 45 wr->x = wr->y = wr->w = wr->h = 0; 46 47 mask = RLayoutXParseGeometry(Scr->Layout, geom, &wr->x, &wr->y, 48 (unsigned int *) &wr->w, 49 (unsigned int *) &wr->h); 50 51 if(mask & XNegative) { 52 wr->x += Scr->rootw - wr->w; 53 } 54 if(mask & YNegative) { 55 wr->y += Scr->rooth - wr->h; 56 } 57 58 return (&(wr->clientlist)); 59} 60 61 62/* 63 * Called during startup after the config parsing (which would hit 64 * AddWindowRegion() above) to do some further setup. 65 */ 66void 67CreateWindowRegions(void) 68{ 69 WindowRegion *wr, *wr1 = NULL, *wr2 = NULL; 70 WorkSpace *wl; 71 72 for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { 73 wl->FirstWindowRegion = NULL; 74 wr2 = NULL; 75 for(wr = Scr->FirstWindowRegion; wr != NULL; wr = wr->next) { 76 wr1 = malloc(sizeof(WindowRegion)); 77 *wr1 = *wr; 78 wr1->entries = calloc(1, sizeof(WindowEntry)); 79 wr1->entries->x = wr1->x; 80 wr1->entries->y = wr1->y; 81 wr1->entries->w = wr1->w; 82 wr1->entries->h = wr1->h; 83 if(wr2) { 84 wr2->next = wr1; 85 } 86 else { 87 wl->FirstWindowRegion = wr1; 88 } 89 wr2 = wr1; 90 } 91 if(wr1) { 92 wr1->next = NULL; 93 } 94 } 95} 96 97 98/* 99 * Funcs for putting windows into and taking them out of regions. 100 * Similarly to icons in IconRegion's, this writes the coordinates into 101 * final_[xy] after setting up the Window Region/Entry structures and 102 * stashing them in tmp_win as necessary. Or it doesn't have anything to 103 * do (like if the user doesn't have WindowRegion's config'd), and it 104 * doesn't touch anything and returns false. 105 */ 106bool 107PlaceWindowInRegion(TwmWindow *tmp_win, int *final_x, int *final_y) 108{ 109 WindowRegion *wr; 110 WindowEntry *we; 111 int w, h; 112 WorkSpace *wl; 113 114 if(!Scr->FirstWindowRegion) { 115 return false; 116 } 117 for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { 118 if(OCCUPY(tmp_win, wl)) { 119 break; 120 } 121 } 122 if(!wl) { 123 return false; 124 } 125 w = tmp_win->frame_width; 126 h = tmp_win->frame_height; 127 we = NULL; 128 for(wr = wl->FirstWindowRegion; wr; wr = wr->next) { 129 if(LookInList(wr->clientlist, tmp_win->name, &tmp_win->class)) { 130 for(we = wr->entries; we; we = we->next) { 131 if(we->used) { 132 continue; 133 } 134 if(we->w >= w && we->h >= h) { 135 break; 136 } 137 } 138 if(we) { 139 break; 140 } 141 } 142 } 143 tmp_win->wr = NULL; 144 if(!we) { 145 return false; 146 } 147 148 splitWindowRegionEntry(we, wr->grav1, wr->grav2, w, h); 149 we->used = true; 150 we->twm_win = tmp_win; 151 *final_x = we->x; 152 *final_y = we->y; 153 tmp_win->wr = wr; 154 return true; 155} 156 157 158/* 159 * Taking a window out of a region. Doesn't do anything with the 160 * _window_, just disconnects it from the data structures describing the 161 * regions and entries. 162 */ 163void 164RemoveWindowFromRegion(TwmWindow *tmp_win) 165{ 166 WindowEntry *we, *wp, *wn; 167 WindowRegion *wr; 168 WorkSpace *wl; 169 170 if(!Scr->FirstWindowRegion) { 171 return; 172 } 173 we = NULL; 174 for(wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { 175 we = findWindowEntry(wl, tmp_win, &wr); 176 if(we) { 177 break; 178 } 179 } 180 if(!we) { 181 return; 182 } 183 184 we->twm_win = NULL; 185 we->used = false; 186 wp = prevWindowEntry(we, wr); 187 wn = we->next; 188 for(;;) { 189 if(wp && wp->used == false && 190 ((wp->x == we->x && wp->w == we->w) || 191 (wp->y == we->y && wp->h == we->h))) { 192 wp->next = we->next; 193 mergeWindowEntries(we, wp); 194 free(we); 195 we = wp; 196 wp = prevWindowEntry(wp, wr); 197 } 198 else if(wn && wn->used == false && 199 ((wn->x == we->x && wn->w == we->w) || 200 (wn->y == we->y && wn->h == we->h))) { 201 we->next = wn->next; 202 mergeWindowEntries(wn, we); 203 free(wn); 204 wn = we->next; 205 } 206 else { 207 break; 208 } 209 } 210} 211 212 213/* 214 * Creating a new space inside a region. 215 * 216 * x-ref comment on splitIconRegionEntry() for grodiness. 217 */ 218static void 219splitWindowRegionEntry(WindowEntry *we, RegGravity grav1, RegGravity grav2, 220 int w, int h) 221{ 222 switch(grav1) { 223 case GRAV_NORTH: 224 case GRAV_SOUTH: 225 if(w != we->w) { 226 splitWindowRegionEntry(we, grav2, grav1, w, we->h); 227 } 228 if(h != we->h) { 229 WindowEntry *new = calloc(1, sizeof(WindowEntry)); 230 new->next = we->next; 231 we->next = new; 232 new->x = we->x; 233 new->h = (we->h - h); 234 new->w = we->w; 235 we->h = h; 236 if(grav1 == GRAV_SOUTH) { 237 new->y = we->y; 238 we->y = new->y + new->h; 239 } 240 else { 241 new->y = we->y + we->h; 242 } 243 } 244 break; 245 case GRAV_EAST: 246 case GRAV_WEST: 247 if(h != we->h) { 248 splitWindowRegionEntry(we, grav2, grav1, we->w, h); 249 } 250 if(w != we->w) { 251 WindowEntry *new = calloc(1, sizeof(WindowEntry)); 252 new->next = we->next; 253 we->next = new; 254 new->y = we->y; 255 new->w = (we->w - w); 256 new->h = we->h; 257 we->w = w; 258 if(grav1 == GRAV_EAST) { 259 new->x = we->x; 260 we->x = new->x + new->w; 261 } 262 else { 263 new->x = we->x + we->w; 264 } 265 } 266 break; 267 } 268} 269 270 271/* 272 * Utils for finding and merging various WindowEntry's 273 */ 274static WindowEntry * 275findWindowEntry(WorkSpace *wl, TwmWindow *tmp_win, WindowRegion **wrp) 276{ 277 WindowRegion *wr; 278 WindowEntry *we; 279 280 for(wr = wl->FirstWindowRegion; wr; wr = wr->next) { 281 for(we = wr->entries; we; we = we->next) { 282 if(we->twm_win == tmp_win) { 283 if(wrp) { 284 *wrp = wr; 285 } 286 return we; 287 } 288 } 289 } 290 return NULL; 291} 292 293 294static WindowEntry * 295prevWindowEntry(WindowEntry *we, WindowRegion *wr) 296{ 297 WindowEntry *wp; 298 299 if(we == wr->entries) { 300 return 0; 301 } 302 for(wp = wr->entries; wp->next != we; wp = wp->next); 303 return wp; 304} 305 306 307static void 308mergeWindowEntries(WindowEntry *old, WindowEntry *we) 309{ 310 if(old->y == we->y) { 311 we->w = old->w + we->w; 312 if(old->x < we->x) { 313 we->x = old->x; 314 } 315 } 316 else { 317 we->h = old->h + we->h; 318 if(old->y < we->y) { 319 we->y = old->y; 320 } 321 } 322} 323