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