10bbfda8aSnia/* 20bbfda8aSnia * Various operations done on windows. 30bbfda8aSnia */ 40bbfda8aSnia 50bbfda8aSnia#include "ctwm.h" 60bbfda8aSnia 70bbfda8aSnia#include <stdio.h> 80bbfda8aSnia 90bbfda8aSnia#include "animate.h" 100bbfda8aSnia#include "colormaps.h" 110bbfda8aSnia#include "drawing.h" 120bbfda8aSnia#include "events.h" 130bbfda8aSnia#include "iconmgr.h" 140bbfda8aSnia#include "image.h" 150bbfda8aSnia#include "otp.h" 160bbfda8aSnia#include "screen.h" 170bbfda8aSnia#include "win_decorations.h" 180bbfda8aSnia#include "win_iconify.h" 190bbfda8aSnia#include "win_ops.h" 200bbfda8aSnia#include "win_utils.h" 210bbfda8aSnia 220bbfda8aSnia 230bbfda8aSnia/* 240bbfda8aSnia * Update the visuals of a window (e.g., its own decorations and its 250bbfda8aSnia * representation in the icon manager) for having/losing focus. 260bbfda8aSnia * 270bbfda8aSnia * Formerly in util.c 280bbfda8aSnia */ 290bbfda8aSniavoid 300bbfda8aSniaSetFocusVisualAttributes(TwmWindow *tmp_win, bool focus) 310bbfda8aSnia{ 320bbfda8aSnia if(! tmp_win) { 330bbfda8aSnia return; 340bbfda8aSnia } 350bbfda8aSnia 360bbfda8aSnia if(focus == tmp_win->hasfocusvisible) { 370bbfda8aSnia return; 380bbfda8aSnia } 390bbfda8aSnia if(tmp_win->highlight) { 400bbfda8aSnia if(Scr->use3Dborders) { 410bbfda8aSnia PaintBorders(tmp_win, focus); 420bbfda8aSnia } 430bbfda8aSnia else { 440bbfda8aSnia if(focus) { 450bbfda8aSnia XSetWindowBorder(dpy, tmp_win->frame, tmp_win->borderC.back); 460bbfda8aSnia if(tmp_win->title_w) { 470bbfda8aSnia XSetWindowBorder(dpy, tmp_win->title_w, tmp_win->borderC.back); 480bbfda8aSnia } 490bbfda8aSnia } 500bbfda8aSnia else { 510bbfda8aSnia /* 520bbfda8aSnia * XXX It seems possible this could be replaced by a 530bbfda8aSnia * single global 'gray' pixmap; I don't think it actually 540bbfda8aSnia * varies per window, and I don't see any obvious reason 550bbfda8aSnia * it can't be reused, so we may be able to save an 560bbfda8aSnia * allocation for each window by doing so... 570bbfda8aSnia */ 580bbfda8aSnia XSetWindowBorderPixmap(dpy, tmp_win->frame, tmp_win->gray); 590bbfda8aSnia if(tmp_win->title_w) { 600bbfda8aSnia XSetWindowBorderPixmap(dpy, tmp_win->title_w, tmp_win->gray); 610bbfda8aSnia } 620bbfda8aSnia } 630bbfda8aSnia } 640bbfda8aSnia } 650bbfda8aSnia 660bbfda8aSnia if(focus) { 670bbfda8aSnia bool hil = false; 680bbfda8aSnia 690bbfda8aSnia if(tmp_win->lolite_wl) { 700bbfda8aSnia XUnmapWindow(dpy, tmp_win->lolite_wl); 710bbfda8aSnia } 720bbfda8aSnia if(tmp_win->lolite_wr) { 730bbfda8aSnia XUnmapWindow(dpy, tmp_win->lolite_wr); 740bbfda8aSnia } 750bbfda8aSnia if(tmp_win->hilite_wl) { 760bbfda8aSnia XMapWindow(dpy, tmp_win->hilite_wl); 770bbfda8aSnia hil = true; 780bbfda8aSnia } 790bbfda8aSnia if(tmp_win->hilite_wr) { 800bbfda8aSnia XMapWindow(dpy, tmp_win->hilite_wr); 810bbfda8aSnia hil = true; 820bbfda8aSnia } 830bbfda8aSnia if(hil && tmp_win->HiliteImage && tmp_win->HiliteImage->next) { 840bbfda8aSnia MaybeAnimate = true; 850bbfda8aSnia } 860bbfda8aSnia if(tmp_win->iconmanagerlist) { 870bbfda8aSnia ActiveIconManager(tmp_win->iconmanagerlist); 880bbfda8aSnia } 890bbfda8aSnia } 900bbfda8aSnia else { 910bbfda8aSnia if(tmp_win->hilite_wl) { 920bbfda8aSnia XUnmapWindow(dpy, tmp_win->hilite_wl); 930bbfda8aSnia } 940bbfda8aSnia if(tmp_win->hilite_wr) { 950bbfda8aSnia XUnmapWindow(dpy, tmp_win->hilite_wr); 960bbfda8aSnia } 970bbfda8aSnia if(tmp_win->lolite_wl) { 980bbfda8aSnia XMapWindow(dpy, tmp_win->lolite_wl); 990bbfda8aSnia } 1000bbfda8aSnia if(tmp_win->lolite_wr) { 1010bbfda8aSnia XMapWindow(dpy, tmp_win->lolite_wr); 1020bbfda8aSnia } 1030bbfda8aSnia if(tmp_win->iconmanagerlist) { 1040bbfda8aSnia NotActiveIconManager(tmp_win->iconmanagerlist); 1050bbfda8aSnia } 1060bbfda8aSnia } 1070bbfda8aSnia if(Scr->use3Dtitles && Scr->SunkFocusWindowTitle && tmp_win->title_height) { 1080bbfda8aSnia ButtonState bs; 1090bbfda8aSnia 1100bbfda8aSnia bs = focus ? on : off; 1110bbfda8aSnia Draw3DBorder(tmp_win->title_w, Scr->TBInfo.titlex, 0, 1120bbfda8aSnia tmp_win->title_width - Scr->TBInfo.titlex - 1130bbfda8aSnia Scr->TBInfo.rightoff - Scr->TitlePadding, 1140bbfda8aSnia Scr->TitleHeight, Scr->TitleShadowDepth, 1150bbfda8aSnia tmp_win->title, bs, false, false); 1160bbfda8aSnia } 1170bbfda8aSnia tmp_win->hasfocusvisible = focus; 1180bbfda8aSnia} 1190bbfda8aSnia 1200bbfda8aSnia 1210bbfda8aSnia/* 1220bbfda8aSnia * Shift the focus to a given window, and do whatever subsidiary ops that 1230bbfda8aSnia * entails. 1240bbfda8aSnia * 1250bbfda8aSnia * Formerly in util.c 1260bbfda8aSnia */ 1270bbfda8aSniavoid 1280bbfda8aSniaSetFocus(TwmWindow *tmp_win, Time tim) 1290bbfda8aSnia{ 1300bbfda8aSnia Window w = (tmp_win ? tmp_win->w : PointerRoot); 1310bbfda8aSnia bool f_iconmgr = false; 1320bbfda8aSnia 1330bbfda8aSnia if(Scr->Focus && (Scr->Focus->isiconmgr)) { 1340bbfda8aSnia f_iconmgr = true; 1350bbfda8aSnia } 1360bbfda8aSnia if(Scr->SloppyFocus && (w == PointerRoot) && (!f_iconmgr)) { 1370bbfda8aSnia return; 1380bbfda8aSnia } 1390bbfda8aSnia 1400bbfda8aSnia XSetInputFocus(dpy, w, RevertToPointerRoot, tim); 1410bbfda8aSnia#ifdef EWMH 1420bbfda8aSnia EwmhSet_NET_ACTIVE_WINDOW(w); 1430bbfda8aSnia#endif 1440bbfda8aSnia if(Scr->Focus == tmp_win) { 1450bbfda8aSnia return; 1460bbfda8aSnia } 1470bbfda8aSnia 1480bbfda8aSnia if(Scr->Focus) { 1490bbfda8aSnia if(Scr->Focus->AutoSqueeze && !Scr->Focus->squeezed) { 1500bbfda8aSnia AutoSqueeze(Scr->Focus); 1510bbfda8aSnia } 1520bbfda8aSnia SetFocusVisualAttributes(Scr->Focus, false); 1530bbfda8aSnia#ifdef EWMH 1540bbfda8aSnia // Priority may change when focus does 1550bbfda8aSnia if(OtpIsFocusDependent(Scr->Focus)) { 1560bbfda8aSnia OtpUnfocusWindow(Scr->Focus); 1570bbfda8aSnia // That Scr->Focus = NULL's internally for us, but we don't 1580bbfda8aSnia // care, since we're about to reset it if we need to. 1590bbfda8aSnia } 1600bbfda8aSnia#endif 1610bbfda8aSnia } 1620bbfda8aSnia 1630bbfda8aSnia if(tmp_win) { 1640bbfda8aSnia if(tmp_win->AutoSqueeze && tmp_win->squeezed) { 1650bbfda8aSnia AutoSqueeze(tmp_win); 1660bbfda8aSnia } 1670bbfda8aSnia SetFocusVisualAttributes(tmp_win, true); 1680bbfda8aSnia#ifdef EWMH 1690bbfda8aSnia // Priority may change when focus does 1700bbfda8aSnia if(OtpIsFocusDependent(tmp_win)) { 1710bbfda8aSnia OtpFocusWindow(tmp_win); 1720bbfda8aSnia // Pre-sets Scr->Focus 1730bbfda8aSnia } 1740bbfda8aSnia#endif 1750bbfda8aSnia } 1760bbfda8aSnia 1770bbfda8aSnia // in the EWMH cases, this was already done. 1780bbfda8aSnia Scr->Focus = tmp_win; 1790bbfda8aSnia 1800bbfda8aSnia return; 1810bbfda8aSnia} 1820bbfda8aSnia 1830bbfda8aSnia 1840bbfda8aSnia/* 1850bbfda8aSnia * Move the focus straight to the root, with associated cleanup. 1860bbfda8aSnia * 1870bbfda8aSnia * Formerly in menus.c 1880bbfda8aSnia */ 1890bbfda8aSniavoid FocusOnRoot(void) 1900bbfda8aSnia{ 1910bbfda8aSnia SetFocus(NULL, EventTime); 1920bbfda8aSnia InstallColormaps(0, &Scr->RootColormaps); 1930bbfda8aSnia if(! Scr->ClickToFocus) { 1940bbfda8aSnia Scr->FocusRoot = true; 1950bbfda8aSnia } 1960bbfda8aSnia} 1970bbfda8aSnia 1980bbfda8aSnia 1990bbfda8aSnia/* 2000bbfda8aSnia * Handle doing squeezing bits for AutoSqueeze{} windows. 2010bbfda8aSnia * 2020bbfda8aSnia * Formerly in menus.c 2030bbfda8aSnia */ 2040bbfda8aSniavoid 2050bbfda8aSniaAutoSqueeze(TwmWindow *tmp_win) 2060bbfda8aSnia{ 2070bbfda8aSnia if(tmp_win->isiconmgr) { 2080bbfda8aSnia return; 2090bbfda8aSnia } 2100bbfda8aSnia if(Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) { 2110bbfda8aSnia OtpRaise(tmp_win, WinWin); 2120bbfda8aSnia } 2130bbfda8aSnia Squeeze(tmp_win); 2140bbfda8aSnia} 2150bbfda8aSnia 2160bbfda8aSnia 2170bbfda8aSnia/* 2180bbfda8aSnia * Toggle a window's squeezed state. 2190bbfda8aSnia * 2200bbfda8aSnia * Formerly in menus.c 2210bbfda8aSnia */ 2220bbfda8aSniavoid 2230bbfda8aSniaSqueeze(TwmWindow *tmp_win) 2240bbfda8aSnia{ 2250bbfda8aSnia long fx, fy, savex, savey; 2260bbfda8aSnia int neww, newh; 2270bbfda8aSnia bool south; 2280bbfda8aSnia int grav = ((tmp_win->hints.flags & PWinGravity) 2290bbfda8aSnia ? tmp_win->hints.win_gravity : NorthWestGravity); 2300bbfda8aSnia long eventMask; 2310bbfda8aSnia if(tmp_win->squeezed) { 232b18c2d1eSnia tmp_win->squeezed = false; 2330bbfda8aSnia#ifdef EWMH 2340bbfda8aSnia EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED); 2350bbfda8aSnia#endif /* EWMH */ 2360bbfda8aSnia if(!tmp_win->isicon) { 2370bbfda8aSnia XMapWindow(dpy, tmp_win->w); 2380bbfda8aSnia } 2390bbfda8aSnia SetupWindow(tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y, 2400bbfda8aSnia tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1); 2410bbfda8aSnia ReMapTransients(tmp_win); 2420bbfda8aSnia return; 2430bbfda8aSnia } 2440bbfda8aSnia 2450bbfda8aSnia newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D; 2460bbfda8aSnia if(newh < 3) { 2470bbfda8aSnia XBell(dpy, 0); 2480bbfda8aSnia return; 2490bbfda8aSnia } 2500bbfda8aSnia switch(grav) { 2510bbfda8aSnia case SouthWestGravity : 2520bbfda8aSnia case SouthGravity : 2530bbfda8aSnia case SouthEastGravity : 2540bbfda8aSnia south = true; 2550bbfda8aSnia break; 2560bbfda8aSnia default : 2570bbfda8aSnia south = false; 2580bbfda8aSnia break; 2590bbfda8aSnia } 2600bbfda8aSnia if(tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) { 2610bbfda8aSnia south = false; 2620bbfda8aSnia } 2630bbfda8aSnia 2640bbfda8aSnia tmp_win->squeezed = true; 2650bbfda8aSnia tmp_win->actual_frame_width = tmp_win->frame_width; 2660bbfda8aSnia tmp_win->actual_frame_height = tmp_win->frame_height; 2670bbfda8aSnia savex = fx = tmp_win->frame_x; 2680bbfda8aSnia savey = fy = tmp_win->frame_y; 2690bbfda8aSnia neww = tmp_win->actual_frame_width; 2700bbfda8aSnia if(south) { 2710bbfda8aSnia fy += tmp_win->frame_height - newh; 2720bbfda8aSnia } 2730bbfda8aSnia if(tmp_win->squeeze_info) { 274b18c2d1eSnia fx += tmp_win->title_x + tmp_win->frame_bw - tmp_win->frame_bw3D; 275b18c2d1eSnia neww = tmp_win->title_width + 2 * tmp_win->frame_bw3D; 2760bbfda8aSnia } 2770bbfda8aSnia 2780bbfda8aSnia eventMask = mask_out_event(tmp_win->w, StructureNotifyMask); 2790bbfda8aSnia#ifdef EWMH 2800bbfda8aSnia EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_SHADED); 2810bbfda8aSnia#endif /* EWMH */ 2820bbfda8aSnia XUnmapWindow(dpy, tmp_win->w); 2830bbfda8aSnia restore_mask(tmp_win->w, eventMask); 2840bbfda8aSnia 2850bbfda8aSnia if(fx + neww >= Scr->rootw - Scr->BorderRight) { 2860bbfda8aSnia fx = Scr->rootw - Scr->BorderRight - neww; 2870bbfda8aSnia } 2880bbfda8aSnia if(fy + newh >= Scr->rooth - Scr->BorderBottom) { 2890bbfda8aSnia fy = Scr->rooth - Scr->BorderBottom - newh; 2900bbfda8aSnia } 2910bbfda8aSnia SetupWindow(tmp_win, fx, fy, neww, newh, -1); 2920bbfda8aSnia tmp_win->actual_frame_x = savex; 2930bbfda8aSnia tmp_win->actual_frame_y = savey; 2940bbfda8aSnia 2950bbfda8aSnia /* Now make the group members disappear */ 2960bbfda8aSnia UnmapTransients(tmp_win, false, eventMask); 2970bbfda8aSnia} 2980bbfda8aSnia 2990bbfda8aSnia 3000bbfda8aSnia/*********************************************************************** 3010bbfda8aSnia * 3020bbfda8aSnia * Procedure: 3030bbfda8aSnia * MoveOutline - move a window outline 3040bbfda8aSnia * 3050bbfda8aSnia * Inputs: 3060bbfda8aSnia * root - the window we are outlining 3070bbfda8aSnia * x - upper left x coordinate 3080bbfda8aSnia * y - upper left y coordinate 3090bbfda8aSnia * width - the width of the rectangle 3100bbfda8aSnia * height - the height of the rectangle 3110bbfda8aSnia * bw - the border width of the frame 3120bbfda8aSnia * th - title height 3130bbfda8aSnia * 3140bbfda8aSnia *********************************************************************** 3150bbfda8aSnia */ 3160bbfda8aSniavoid 3170bbfda8aSniaMoveOutline(Window root, int x, int y, int width, int height, int bw, int th) 3180bbfda8aSnia{ 3190bbfda8aSnia static int lastx = 0; 3200bbfda8aSnia static int lasty = 0; 3210bbfda8aSnia static int lastWidth = 0; 3220bbfda8aSnia static int lastHeight = 0; 3230bbfda8aSnia static int lastBW = 0; 3240bbfda8aSnia static int lastTH = 0; 3250bbfda8aSnia int xl, xr, yt, yb, xinnerl, xinnerr, yinnert, yinnerb; 3260bbfda8aSnia int xthird, ythird; 3270bbfda8aSnia XSegment outline[18]; 3280bbfda8aSnia XSegment *r; 3290bbfda8aSnia 3300bbfda8aSnia if(x == lastx && y == lasty && width == lastWidth && height == lastHeight 3310bbfda8aSnia && lastBW == bw && th == lastTH) { 3320bbfda8aSnia return; 3330bbfda8aSnia } 3340bbfda8aSnia 3350bbfda8aSnia r = outline; 3360bbfda8aSnia 3370bbfda8aSnia#define DRAWIT() \ 3380bbfda8aSnia if (lastWidth || lastHeight) \ 3390bbfda8aSnia { \ 3400bbfda8aSnia xl = lastx; \ 3410bbfda8aSnia xr = lastx + lastWidth - 1; \ 3420bbfda8aSnia yt = lasty; \ 3430bbfda8aSnia yb = lasty + lastHeight - 1; \ 3440bbfda8aSnia xinnerl = xl + lastBW; \ 3450bbfda8aSnia xinnerr = xr - lastBW; \ 3460bbfda8aSnia yinnert = yt + lastTH + lastBW; \ 3470bbfda8aSnia yinnerb = yb - lastBW; \ 3480bbfda8aSnia xthird = (xinnerr - xinnerl) / 3; \ 3490bbfda8aSnia ythird = (yinnerb - yinnert) / 3; \ 3500bbfda8aSnia \ 3510bbfda8aSnia r->x1 = xl; \ 3520bbfda8aSnia r->y1 = yt; \ 3530bbfda8aSnia r->x2 = xr; \ 3540bbfda8aSnia r->y2 = yt; \ 3550bbfda8aSnia r++; \ 3560bbfda8aSnia \ 3570bbfda8aSnia r->x1 = xl; \ 3580bbfda8aSnia r->y1 = yb; \ 3590bbfda8aSnia r->x2 = xr; \ 3600bbfda8aSnia r->y2 = yb; \ 3610bbfda8aSnia r++; \ 3620bbfda8aSnia \ 3630bbfda8aSnia r->x1 = xl; \ 3640bbfda8aSnia r->y1 = yt; \ 3650bbfda8aSnia r->x2 = xl; \ 3660bbfda8aSnia r->y2 = yb; \ 3670bbfda8aSnia r++; \ 3680bbfda8aSnia \ 3690bbfda8aSnia r->x1 = xr; \ 3700bbfda8aSnia r->y1 = yt; \ 3710bbfda8aSnia r->x2 = xr; \ 3720bbfda8aSnia r->y2 = yb; \ 3730bbfda8aSnia r++; \ 3740bbfda8aSnia \ 3750bbfda8aSnia r->x1 = xinnerl + xthird; \ 3760bbfda8aSnia r->y1 = yinnert; \ 3770bbfda8aSnia r->x2 = r->x1; \ 3780bbfda8aSnia r->y2 = yinnerb; \ 3790bbfda8aSnia r++; \ 3800bbfda8aSnia \ 3810bbfda8aSnia r->x1 = xinnerl + (2 * xthird); \ 3820bbfda8aSnia r->y1 = yinnert; \ 3830bbfda8aSnia r->x2 = r->x1; \ 3840bbfda8aSnia r->y2 = yinnerb; \ 3850bbfda8aSnia r++; \ 3860bbfda8aSnia \ 3870bbfda8aSnia r->x1 = xinnerl; \ 3880bbfda8aSnia r->y1 = yinnert + ythird; \ 3890bbfda8aSnia r->x2 = xinnerr; \ 3900bbfda8aSnia r->y2 = r->y1; \ 3910bbfda8aSnia r++; \ 3920bbfda8aSnia \ 3930bbfda8aSnia r->x1 = xinnerl; \ 3940bbfda8aSnia r->y1 = yinnert + (2 * ythird); \ 3950bbfda8aSnia r->x2 = xinnerr; \ 3960bbfda8aSnia r->y2 = r->y1; \ 3970bbfda8aSnia r++; \ 3980bbfda8aSnia \ 3990bbfda8aSnia if (lastTH != 0) { \ 4000bbfda8aSnia r->x1 = xl; \ 4010bbfda8aSnia r->y1 = yt + lastTH; \ 4020bbfda8aSnia r->x2 = xr; \ 4030bbfda8aSnia r->y2 = r->y1; \ 4040bbfda8aSnia r++; \ 4050bbfda8aSnia } \ 4060bbfda8aSnia } 4070bbfda8aSnia 4080bbfda8aSnia /* undraw the old one, if any */ 4090bbfda8aSnia DRAWIT(); 4100bbfda8aSnia 4110bbfda8aSnia lastx = x; 4120bbfda8aSnia lasty = y; 4130bbfda8aSnia lastWidth = width; 4140bbfda8aSnia lastHeight = height; 4150bbfda8aSnia lastBW = bw; 4160bbfda8aSnia lastTH = th; 4170bbfda8aSnia 4180bbfda8aSnia /* draw the new one, if any */ 4190bbfda8aSnia DRAWIT(); 4200bbfda8aSnia 4210bbfda8aSnia#undef DRAWIT 4220bbfda8aSnia 4230bbfda8aSnia 4240bbfda8aSnia if(r != outline) { 4250bbfda8aSnia XDrawSegments(dpy, root, Scr->DrawGC, outline, r - outline); 4260bbfda8aSnia } 4270bbfda8aSnia} 428