win_ops.c revision 0bbfda8a
1/* 2 * Various operations done on windows. 3 */ 4 5#include "ctwm.h" 6 7#include <stdio.h> 8 9#include "animate.h" 10#include "colormaps.h" 11#include "drawing.h" 12#include "events.h" 13#include "iconmgr.h" 14#include "image.h" 15#include "otp.h" 16#include "screen.h" 17#include "win_decorations.h" 18#include "win_iconify.h" 19#include "win_ops.h" 20#include "win_utils.h" 21 22 23/* 24 * Update the visuals of a window (e.g., its own decorations and its 25 * representation in the icon manager) for having/losing focus. 26 * 27 * Formerly in util.c 28 */ 29void 30SetFocusVisualAttributes(TwmWindow *tmp_win, bool focus) 31{ 32 if(! tmp_win) { 33 return; 34 } 35 36 if(focus == tmp_win->hasfocusvisible) { 37 return; 38 } 39 if(tmp_win->highlight) { 40 if(Scr->use3Dborders) { 41 PaintBorders(tmp_win, focus); 42 } 43 else { 44 if(focus) { 45 XSetWindowBorder(dpy, tmp_win->frame, tmp_win->borderC.back); 46 if(tmp_win->title_w) { 47 XSetWindowBorder(dpy, tmp_win->title_w, tmp_win->borderC.back); 48 } 49 } 50 else { 51 /* 52 * XXX It seems possible this could be replaced by a 53 * single global 'gray' pixmap; I don't think it actually 54 * varies per window, and I don't see any obvious reason 55 * it can't be reused, so we may be able to save an 56 * allocation for each window by doing so... 57 */ 58 XSetWindowBorderPixmap(dpy, tmp_win->frame, tmp_win->gray); 59 if(tmp_win->title_w) { 60 XSetWindowBorderPixmap(dpy, tmp_win->title_w, tmp_win->gray); 61 } 62 } 63 } 64 } 65 66 if(focus) { 67 bool hil = false; 68 69 if(tmp_win->lolite_wl) { 70 XUnmapWindow(dpy, tmp_win->lolite_wl); 71 } 72 if(tmp_win->lolite_wr) { 73 XUnmapWindow(dpy, tmp_win->lolite_wr); 74 } 75 if(tmp_win->hilite_wl) { 76 XMapWindow(dpy, tmp_win->hilite_wl); 77 hil = true; 78 } 79 if(tmp_win->hilite_wr) { 80 XMapWindow(dpy, tmp_win->hilite_wr); 81 hil = true; 82 } 83 if(hil && tmp_win->HiliteImage && tmp_win->HiliteImage->next) { 84 MaybeAnimate = true; 85 } 86 if(tmp_win->iconmanagerlist) { 87 ActiveIconManager(tmp_win->iconmanagerlist); 88 } 89 } 90 else { 91 if(tmp_win->hilite_wl) { 92 XUnmapWindow(dpy, tmp_win->hilite_wl); 93 } 94 if(tmp_win->hilite_wr) { 95 XUnmapWindow(dpy, tmp_win->hilite_wr); 96 } 97 if(tmp_win->lolite_wl) { 98 XMapWindow(dpy, tmp_win->lolite_wl); 99 } 100 if(tmp_win->lolite_wr) { 101 XMapWindow(dpy, tmp_win->lolite_wr); 102 } 103 if(tmp_win->iconmanagerlist) { 104 NotActiveIconManager(tmp_win->iconmanagerlist); 105 } 106 } 107 if(Scr->use3Dtitles && Scr->SunkFocusWindowTitle && tmp_win->title_height) { 108 ButtonState bs; 109 110 bs = focus ? on : off; 111 Draw3DBorder(tmp_win->title_w, Scr->TBInfo.titlex, 0, 112 tmp_win->title_width - Scr->TBInfo.titlex - 113 Scr->TBInfo.rightoff - Scr->TitlePadding, 114 Scr->TitleHeight, Scr->TitleShadowDepth, 115 tmp_win->title, bs, false, false); 116 } 117 tmp_win->hasfocusvisible = focus; 118} 119 120 121/* 122 * Shift the focus to a given window, and do whatever subsidiary ops that 123 * entails. 124 * 125 * Formerly in util.c 126 */ 127void 128SetFocus(TwmWindow *tmp_win, Time tim) 129{ 130 Window w = (tmp_win ? tmp_win->w : PointerRoot); 131 bool f_iconmgr = false; 132 133 if(Scr->Focus && (Scr->Focus->isiconmgr)) { 134 f_iconmgr = true; 135 } 136 if(Scr->SloppyFocus && (w == PointerRoot) && (!f_iconmgr)) { 137 return; 138 } 139 140 XSetInputFocus(dpy, w, RevertToPointerRoot, tim); 141#ifdef EWMH 142 EwmhSet_NET_ACTIVE_WINDOW(w); 143#endif 144 if(Scr->Focus == tmp_win) { 145 return; 146 } 147 148 if(Scr->Focus) { 149 if(Scr->Focus->AutoSqueeze && !Scr->Focus->squeezed) { 150 AutoSqueeze(Scr->Focus); 151 } 152 SetFocusVisualAttributes(Scr->Focus, false); 153#ifdef EWMH 154 // Priority may change when focus does 155 if(OtpIsFocusDependent(Scr->Focus)) { 156 OtpUnfocusWindow(Scr->Focus); 157 // That Scr->Focus = NULL's internally for us, but we don't 158 // care, since we're about to reset it if we need to. 159 } 160#endif 161 } 162 163 if(tmp_win) { 164 if(tmp_win->AutoSqueeze && tmp_win->squeezed) { 165 AutoSqueeze(tmp_win); 166 } 167 SetFocusVisualAttributes(tmp_win, true); 168#ifdef EWMH 169 // Priority may change when focus does 170 if(OtpIsFocusDependent(tmp_win)) { 171 OtpFocusWindow(tmp_win); 172 // Pre-sets Scr->Focus 173 } 174#endif 175 } 176 177 // in the EWMH cases, this was already done. 178 Scr->Focus = tmp_win; 179 180 return; 181} 182 183 184/* 185 * Move the focus straight to the root, with associated cleanup. 186 * 187 * Formerly in menus.c 188 */ 189void FocusOnRoot(void) 190{ 191 SetFocus(NULL, EventTime); 192 InstallColormaps(0, &Scr->RootColormaps); 193 if(! Scr->ClickToFocus) { 194 Scr->FocusRoot = true; 195 } 196} 197 198 199/* 200 * Handle doing squeezing bits for AutoSqueeze{} windows. 201 * 202 * Formerly in menus.c 203 */ 204void 205AutoSqueeze(TwmWindow *tmp_win) 206{ 207 if(tmp_win->isiconmgr) { 208 return; 209 } 210 if(Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) { 211 OtpRaise(tmp_win, WinWin); 212 } 213 Squeeze(tmp_win); 214} 215 216 217/* 218 * Toggle a window's squeezed state. 219 * 220 * Formerly in menus.c 221 */ 222void 223Squeeze(TwmWindow *tmp_win) 224{ 225 long fx, fy, savex, savey; 226 int neww, newh; 227 bool south; 228 int grav = ((tmp_win->hints.flags & PWinGravity) 229 ? tmp_win->hints.win_gravity : NorthWestGravity); 230 long eventMask; 231 if(tmp_win->squeezed) { 232 tmp_win->squeezed = False; 233#ifdef EWMH 234 EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED); 235#endif /* EWMH */ 236 if(!tmp_win->isicon) { 237 XMapWindow(dpy, tmp_win->w); 238 } 239 SetupWindow(tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y, 240 tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1); 241 ReMapTransients(tmp_win); 242 return; 243 } 244 245 newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D; 246 if(newh < 3) { 247 XBell(dpy, 0); 248 return; 249 } 250 switch(grav) { 251 case SouthWestGravity : 252 case SouthGravity : 253 case SouthEastGravity : 254 south = true; 255 break; 256 default : 257 south = false; 258 break; 259 } 260 if(tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) { 261 south = false; 262 } 263 264 tmp_win->squeezed = true; 265 tmp_win->actual_frame_width = tmp_win->frame_width; 266 tmp_win->actual_frame_height = tmp_win->frame_height; 267 savex = fx = tmp_win->frame_x; 268 savey = fy = tmp_win->frame_y; 269 neww = tmp_win->actual_frame_width; 270 if(south) { 271 fy += tmp_win->frame_height - newh; 272 } 273 if(tmp_win->squeeze_info) { 274 fx += tmp_win->title_x - tmp_win->frame_bw3D; 275 neww = tmp_win->title_width + 2 * (tmp_win->frame_bw + tmp_win->frame_bw3D); 276 } 277 278 eventMask = mask_out_event(tmp_win->w, StructureNotifyMask); 279#ifdef EWMH 280 EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED); 281#endif /* EWMH */ 282 XUnmapWindow(dpy, tmp_win->w); 283 restore_mask(tmp_win->w, eventMask); 284 285 if(fx + neww >= Scr->rootw - Scr->BorderRight) { 286 fx = Scr->rootw - Scr->BorderRight - neww; 287 } 288 if(fy + newh >= Scr->rooth - Scr->BorderBottom) { 289 fy = Scr->rooth - Scr->BorderBottom - newh; 290 } 291 SetupWindow(tmp_win, fx, fy, neww, newh, -1); 292 tmp_win->actual_frame_x = savex; 293 tmp_win->actual_frame_y = savey; 294 295 /* Now make the group members disappear */ 296 UnmapTransients(tmp_win, false, eventMask); 297} 298 299 300/*********************************************************************** 301 * 302 * Procedure: 303 * MoveOutline - move a window outline 304 * 305 * Inputs: 306 * root - the window we are outlining 307 * x - upper left x coordinate 308 * y - upper left y coordinate 309 * width - the width of the rectangle 310 * height - the height of the rectangle 311 * bw - the border width of the frame 312 * th - title height 313 * 314 *********************************************************************** 315 */ 316void 317MoveOutline(Window root, int x, int y, int width, int height, int bw, int th) 318{ 319 static int lastx = 0; 320 static int lasty = 0; 321 static int lastWidth = 0; 322 static int lastHeight = 0; 323 static int lastBW = 0; 324 static int lastTH = 0; 325 int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb; 326 int xthird, ythird; 327 XSegment outline[18]; 328 XSegment *r; 329 330 if(x == lastx && y == lasty && width == lastWidth && height == lastHeight 331 && lastBW == bw && th == lastTH) { 332 return; 333 } 334 335 r = outline; 336 337#define DRAWIT() \ 338 if (lastWidth || lastHeight) \ 339 { \ 340 xl = lastx; \ 341 xr = lastx + lastWidth - 1; \ 342 yt = lasty; \ 343 yb = lasty + lastHeight - 1; \ 344 xinnerl = xl + lastBW; \ 345 xinnerr = xr - lastBW; \ 346 yinnert = yt + lastTH + lastBW; \ 347 yinnerb = yb - lastBW; \ 348 xthird = (xinnerr - xinnerl) / 3; \ 349 ythird = (yinnerb - yinnert) / 3; \ 350 \ 351 r->x1 = xl; \ 352 r->y1 = yt; \ 353 r->x2 = xr; \ 354 r->y2 = yt; \ 355 r++; \ 356 \ 357 r->x1 = xl; \ 358 r->y1 = yb; \ 359 r->x2 = xr; \ 360 r->y2 = yb; \ 361 r++; \ 362 \ 363 r->x1 = xl; \ 364 r->y1 = yt; \ 365 r->x2 = xl; \ 366 r->y2 = yb; \ 367 r++; \ 368 \ 369 r->x1 = xr; \ 370 r->y1 = yt; \ 371 r->x2 = xr; \ 372 r->y2 = yb; \ 373 r++; \ 374 \ 375 r->x1 = xinnerl + xthird; \ 376 r->y1 = yinnert; \ 377 r->x2 = r->x1; \ 378 r->y2 = yinnerb; \ 379 r++; \ 380 \ 381 r->x1 = xinnerl + (2 * xthird); \ 382 r->y1 = yinnert; \ 383 r->x2 = r->x1; \ 384 r->y2 = yinnerb; \ 385 r++; \ 386 \ 387 r->x1 = xinnerl; \ 388 r->y1 = yinnert + ythird; \ 389 r->x2 = xinnerr; \ 390 r->y2 = r->y1; \ 391 r++; \ 392 \ 393 r->x1 = xinnerl; \ 394 r->y1 = yinnert + (2 * ythird); \ 395 r->x2 = xinnerr; \ 396 r->y2 = r->y1; \ 397 r++; \ 398 \ 399 if (lastTH != 0) { \ 400 r->x1 = xl; \ 401 r->y1 = yt + lastTH; \ 402 r->x2 = xr; \ 403 r->y2 = r->y1; \ 404 r++; \ 405 } \ 406 } 407 408 /* undraw the old one, if any */ 409 DRAWIT(); 410 411 lastx = x; 412 lasty = y; 413 lastWidth = width; 414 lastHeight = height; 415 lastBW = bw; 416 lastTH = th; 417 418 /* draw the new one, if any */ 419 DRAWIT(); 420 421#undef DRAWIT 422 423 424 if(r != outline) { 425 XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline); 426 } 427} 428