/** Stop move. */ void StopMove(ClientNode *np, int doMove, int oldx, int oldy, MaxFlags maxFlags) { int north, south, east, west; Assert(np); Assert(np->controller); (np->controller)(0); np->controller = NULL; SetDefaultCursor(np->parent); UnregisterCallback(SignalMove, NULL); if(!doMove) { np->x = oldx; np->y = oldy; /* Restore maximized status. */ if(maxFlags) { MaximizeClient(np, maxFlags); } return; } GetBorderSize(&np->state, &north, &south, &east, &west); if(np->parent != None) { JXMoveWindow(display, np->parent, np->x - west, np->y - north); } else { JXMoveWindow(display, np->window, np->x - west, np->y - north); } SendConfigureEvent(np); /* Restore maximized status. */ if(maxFlags) { MaximizeClient(np, maxFlags); } }
/** Maximize a client window. */ void MaximizeClient(ClientNode *np, MaxFlags flags) { /* Return if we don't have a client. */ if(np == NULL) { return; } /* Don't allow maximization of full-screen clients. */ if(np->state.status & STAT_FULLSCREEN) { return; } if(!(np->state.border & BORDER_MAX)) { return; } if(np->state.status & STAT_SHADED) { UnshadeClient(np); } RaiseClient(np); FocusClient(np); if(np->state.maxFlags) { /* Undo existing maximization. */ np->x = np->oldx; np->y = np->oldy; np->width = np->oldWidth; np->height = np->oldHeight; np->state.maxFlags = MAX_NONE; } if(flags != MAX_NONE) { /* Maximize if requested. */ PlaceMaximizedClient(np, flags); } WriteState(np); ResetBorder(np); DrawBorder(np); SendConfigureEvent(np); RequirePagerUpdate(); }
/** Stop move. */ void StopMove(ClientNode *np, int doMove, int oldx, int oldy, int hmax, int vmax) { int north, south, east, west; Assert(np); Assert(np->controller); (np->controller)(0); np->controller = NULL; SetDefaultCursor(np->parent); UnregisterCallback(SignalMove, NULL); if(!doMove) { np->x = oldx; np->y = oldy; /* Restore maximized status if only maximized in one direction. */ if((hmax || vmax) && !(hmax && vmax)) { MaximizeClient(np, hmax, vmax); } return; } GetBorderSize(&np->state, &north, &south, &east, &west); JXMoveWindow(display, np->parent, np->x - west, np->y - north); SendConfigureEvent(np); /* Restore maximized status. */ if((hmax || vmax) && !(hmax && vmax)) { MaximizeClient(np, hmax, vmax); } }
/** Move a client window. */ char MoveClient(ClientNode *np, int startx, int starty) { XEvent event; int oldx, oldy; int doMove; int north, south, east, west; int height; MaxFlags maxFlags; Assert(np); if(!(np->state.border & BORDER_MOVE)) { return 0; } if(np->state.status & STAT_FULLSCREEN) { return 0; } GrabMouseForMove(); RegisterCallback(0, SignalMove, NULL); np->controller = MoveController; shouldStopMove = 0; oldx = np->x; oldy = np->y; maxFlags = np->state.maxFlags; if(!(GetMouseMask() & (Button1Mask | Button2Mask))) { StopMove(np, 0, oldx, oldy, maxFlags); return 0; } GetBorderSize(&np->state, &north, &south, &east, &west); startx -= west; starty -= north; currentClient = np; atTop = atBottom = atLeft = atRight = 0; doMove = 0; for(;;) { WaitForEvent(&event); if(shouldStopMove) { np->controller = NULL; SetDefaultCursor(np->parent); UnregisterCallback(SignalMove, NULL); return doMove; } switch(event.type) { case ButtonRelease: if(event.xbutton.button == Button1 || event.xbutton.button == Button2) { StopMove(np, doMove, oldx, oldy, maxFlags); return doMove; } break; case MotionNotify: DiscardMotionEvents(&event, np->window); np->x = event.xmotion.x_root - startx; np->y = event.xmotion.y_root - starty; /* Get the move time used for desktop switching. */ if(!(atLeft | atTop | atRight | atBottom)) { if(event.xmotion.state & Mod1Mask) { moveTime.seconds = 0; moveTime.ms = 0; } else { GetCurrentTime(&moveTime); } } /* Determine if we are at a border for desktop switching. */ atLeft = atTop = atRight = atBottom = 0; if(event.xmotion.x_root == 0) { atLeft = 1; } else if(event.xmotion.x_root == rootWidth - 1) { atRight = 1; } if(event.xmotion.y_root == 0) { atTop = 1; } else if(event.xmotion.y_root == rootHeight - 1) { atBottom = 1; } if(event.xmotion.state & Mod1Mask) { /* Switch desktops immediately if alt is pressed. */ if(atLeft | atRight | atTop | atBottom) { TimeType now; GetCurrentTime(&now); UpdateDesktop(&now); } } else { /* If alt is not pressed, snap to borders. */ DoSnap(np); } if(!doMove && (abs(np->x - oldx) > MOVE_DELTA || abs(np->y - oldy) > MOVE_DELTA)) { if(np->state.maxFlags) { MaximizeClient(np, MAX_NONE); startx = np->width / 2; starty = -north / 2; MoveMouse(np->parent, startx, starty); } CreateMoveWindow(np); doMove = 1; } if(doMove) { if(settings.moveMode == MOVE_OUTLINE) { ClearOutline(); height = north + south; if(!(np->state.status & STAT_SHADED)) { height += np->height; } DrawOutline(np->x - west, np->y - north, np->width + west + east, height); } else { JXMoveWindow(display, np->parent, np->x - west, np->y - north); SendConfigureEvent(np); } UpdateMoveWindow(np); RequirePagerUpdate(); } break; default: break; } } }
/** Move a client window (keyboard or menu initiated). */ char MoveClientKeyboard(ClientNode *np) { XEvent event; int oldx, oldy; int moved; int height; int north, south, east, west; MaxFlags maxFlags; Assert(np); if(!(np->state.border & BORDER_MOVE)) { return 0; } if(np->state.status & STAT_FULLSCREEN) { return 0; } maxFlags = np->state.maxFlags; if(np->state.maxFlags != MAX_NONE) { MaximizeClient(np, MAX_NONE); } if(JUNLIKELY(JXGrabKeyboard(display, np->parent, True, GrabModeAsync, GrabModeAsync, CurrentTime))) { Debug("MoveClient: could not grab keyboard"); return 0; } GrabMouseForMove(); GetBorderSize(&np->state, &north, &south, &east, &west); oldx = np->x; oldy = np->y; RegisterCallback(0, SignalMove, NULL); np->controller = MoveController; shouldStopMove = 0; CreateMoveWindow(np); UpdateMoveWindow(np); MoveMouse(rootWindow, np->x, np->y); DiscardMotionEvents(&event, np->window); if(np->state.status & STAT_SHADED) { height = 0; } else { height = np->height; } for(;;) { WaitForEvent(&event); if(shouldStopMove) { np->controller = NULL; SetDefaultCursor(np->parent); UnregisterCallback(SignalMove, NULL); return 1; } moved = 0; if(event.type == KeyPress) { DiscardKeyEvents(&event, np->window); switch(GetKey(&event.xkey) & 0xFF) { case KEY_UP: if(np->y + height > 0) { np->y -= 10; } break; case KEY_DOWN: if(np->y < rootHeight) { np->y += 10; } break; case KEY_RIGHT: if(np->x < rootWidth) { np->x += 10; } break; case KEY_LEFT: if(np->x + np->width > 0) { np->x -= 10; } break; default: StopMove(np, 1, oldx, oldy, maxFlags); return 1; } MoveMouse(rootWindow, np->x, np->y); DiscardMotionEvents(&event, np->window); moved = 1; } else if(event.type == MotionNotify) { DiscardMotionEvents(&event, np->window); np->x = event.xmotion.x; np->y = event.xmotion.y; moved = 1; } else if(event.type == ButtonRelease) { StopMove(np, 1, oldx, oldy, maxFlags); return 1; } if(moved) { if(settings.moveMode == MOVE_OUTLINE) { ClearOutline(); DrawOutline(np->x - west, np->y - west, np->width + west + east, height + north + west); } else { JXMoveWindow(display, np->parent, np->x - west, np->y - north); SendConfigureEvent(np); } UpdateMoveWindow(np); RequirePagerUpdate(); } } }
/** Move a client window. */ char MoveClient(ClientNode *np, int startx, int starty, int snap) { XEvent event; int oldx, oldy; int doMove; int north, south, east, west; int height; int hmax, vmax; Assert(np); if(!(np->state.border & BORDER_MOVE)) { return 0; } if(np->state.status & STAT_FULLSCREEN) { return 0; } GrabMouseForMove(); RegisterCallback(0, SignalMove, NULL); np->controller = MoveController; shouldStopMove = 0; oldx = np->x; oldy = np->y; vmax = 0; hmax = 0; if(!(GetMouseMask() & (Button1Mask | Button2Mask))) { StopMove(np, 0, oldx, oldy, 0, 0); return 0; } GetBorderSize(&np->state, &north, &south, &east, &west); startx -= west; starty -= north; currentClient = np; atTop = 0; atBottom = 0; atLeft = 0; atRight = 0; doMove = 0; for(;;) { WaitForEvent(&event); if(shouldStopMove) { np->controller = NULL; SetDefaultCursor(np->parent); UnregisterCallback(SignalMove, NULL); return doMove; } switch(event.type) { case ButtonRelease: if(event.xbutton.button == Button1 || event.xbutton.button == Button2) { StopMove(np, doMove, oldx, oldy, hmax, vmax); return doMove; } break; case MotionNotify: DiscardMotionEvents(&event, np->window); np->x = event.xmotion.x_root - startx; np->y = event.xmotion.y_root - starty; GetCurrentTime(&moveTime); atLeft = 0; atTop = 0; atRight = 0; atBottom = 0; if(event.xmotion.x_root == 0) { atLeft = 1; } else if(event.xmotion.x_root == rootWidth - 1) { atRight = 1; } if(event.xmotion.y_root == 0) { atTop = 1; } else if(event.xmotion.y_root == rootHeight - 1) { atBottom = 1; } if(snap) { DoSnap(np); } if(!doMove && (abs(np->x - oldx) > MOVE_DELTA || abs(np->y - oldy) > MOVE_DELTA)) { if(np->state.status & (STAT_HMAX | STAT_VMAX)) { if(np->state.status & STAT_HMAX) { hmax = 1; } if(np->state.status & STAT_VMAX) { vmax = 1; } MaximizeClient(np, 0, 0); startx = np->width / 2; starty = -north / 2; MoveMouse(np->parent, startx, starty); } CreateMoveWindow(np); doMove = 1; } if(doMove) { if(settings.moveMode == MOVE_OUTLINE) { ClearOutline(); height = north + south; if(!(np->state.status & STAT_SHADED)) { height += np->height; } DrawOutline(np->x - west, np->y - north, np->width + west + east, height); } else { JXMoveWindow(display, np->parent, np->x - west, np->y - north); SendConfigureEvent(np); } UpdateMoveWindow(np); UpdatePager(); } break; default: break; } } }
/** Process a configure request. */ void HandleConfigureRequest(const XConfigureRequestEvent *event) { XWindowChanges wc; ClientNode *np; if(HandleDockConfigureRequest(event)) { return; } np = FindClientByWindow(event->window); if(np) { int deltax, deltay; char changed = 0; char resized = 0; GetGravityDelta(np, np->gravity, &deltax, &deltay); if((event->value_mask & CWWidth) && (event->width != np->width)) { switch(np->gravity) { case EastGravity: case NorthEastGravity: case SouthEastGravity: /* Right side should not move. */ np->x -= event->width - np->width; break; case WestGravity: case NorthWestGravity: case SouthWestGravity: /* Left side should not move. */ break; case CenterGravity: /* Center of the window should not move. */ np->x -= (event->width - np->width) / 2; break; default: break; } np->width = event->width; changed = 1; resized = 1; } if((event->value_mask & CWHeight) && (event->height != np->height)) { switch(np->gravity) { case NorthGravity: case NorthEastGravity: case NorthWestGravity: /* Top should not move. */ break; case SouthGravity: case SouthEastGravity: case SouthWestGravity: /* Bottom should not move. */ np->y -= event->height - np->height; break; case CenterGravity: /* Center of the window should not move. */ np->y -= (event->height - np->height) / 2; break; default: break; } np->height = event->height; changed = 1; resized = 1; } if((event->value_mask & CWX) && (event->x - deltax != np->x)) { np->x = event->x - deltax; changed = 1; } if((event->value_mask & CWY) && (event->y - deltay != np->y)) { np->y = event->y - deltay; changed = 1; } /* Update stacking. */ if((event->value_mask & CWStackMode)) { Window above = None; if(event->value_mask & CWSibling) { above = event->above; } RestackClient(np, above, event->detail); } /* Return early if there's nothing to do. */ if(!changed) { return; } if(np->controller) { (np->controller)(0); } if(np->state.maxFlags) { MaximizeClient(np, MAX_NONE); } if(np->state.border & BORDER_CONSTRAIN) { resized = 1; } if(resized) { ConstrainSize(np); ConstrainPosition(np); ResetBorder(np); } else { int north, south, east, west; GetBorderSize(&np->state, &north, &south, &east, &west); if(np->parent != None) { JXMoveWindow(display, np->parent, np->x - west, np->y - north); } else { JXMoveWindow(display, np->window, np->x, np->y); } } SendConfigureEvent(np); RequirePagerUpdate(); } else { /* We don't know about this window, just let the configure through. */ wc.stack_mode = event->detail; wc.sibling = event->above; wc.border_width = event->border_width; wc.x = event->x; wc.y = event->y; wc.width = event->width; wc.height = event->height; JXConfigureWindow(display, event->window, event->value_mask, &wc); } }
/** Handle a _NET_MOVERESIZE_WINDOW request. */ void HandleNetMoveResize(const XClientMessageEvent *event, ClientNode *np) { long flags; int gravity; int deltax, deltay; Assert(event); Assert(np); flags = event->data.l[0] >> 8; gravity = event->data.l[0] & 0xFF; if(gravity == 0) { gravity = np->gravity; } GetGravityDelta(np, gravity, &deltax, &deltay); if(flags & (1 << 2)) { const long width = event->data.l[3]; switch(gravity) { case EastGravity: case NorthEastGravity: case SouthEastGravity: /* Right side should not move. */ np->x -= width - np->width; break; case WestGravity: case NorthWestGravity: case SouthWestGravity: /* Left side should not move. */ break; case CenterGravity: /* Center of the window should not move. */ np->x -= (width - np->width) / 2; break; default: break; } np->width = width; } if(flags & (1 << 3)) { const long height = event->data.l[4]; switch(gravity) { case NorthGravity: case NorthEastGravity: case NorthWestGravity: /* Top should not move. */ break; case SouthGravity: case SouthEastGravity: case SouthWestGravity: /* Bottom should not move. */ np->y -= height - np->height; break; case CenterGravity: /* Center of the window should not move. */ np->y -= (height - np->height) / 2; break; default: break; } np->height = height; } if(flags & (1 << 0)) { np->x = event->data.l[1] - deltax; } if(flags & (1 << 1)) { np->y = event->data.l[2] - deltay; } /* Don't let maximized clients be moved or resized. */ if(JUNLIKELY(np->state.status & STAT_FULLSCREEN)) { SetClientFullScreen(np, 0); } if(JUNLIKELY(np->state.maxFlags)) { MaximizeClient(np, MAX_NONE); } ConstrainSize(np); ResetBorder(np); SendConfigureEvent(np); RequirePagerUpdate(); }
/** Set a client's full screen state. */ void SetClientFullScreen(ClientNode *np, char fullScreen) { XEvent event; int north, south, east, west; BoundingBox box; const ScreenType *sp; Assert(np); /* Make sure there's something to do. */ if(!fullScreen == !(np->state.status & STAT_FULLSCREEN)) { return; } if(!(np->state.border & BORDER_FULLSCREEN)) { return; } if(np->state.status & STAT_SHADED) { UnshadeClient(np); } if(fullScreen) { np->state.status |= STAT_FULLSCREEN; if(!(np->state.maxFlags)) { np->oldx = np->x; np->oldy = np->y; np->oldWidth = np->width; np->oldHeight = np->height; } sp = GetCurrentScreen(np->x, np->y); GetScreenBounds(sp, &box); GetBorderSize(&np->state, &north, &south, &east, &west); box.x += west; box.y += north; box.width -= east + west; box.height -= north + south; np->x = box.x; np->y = box.y; np->width = box.width; np->height = box.height; ResetBorder(np); } else { np->state.status &= ~STAT_FULLSCREEN; np->x = np->oldx; np->y = np->oldy; np->width = np->oldWidth; np->height = np->oldHeight; ConstrainSize(np); ConstrainPosition(np); if(np->state.maxFlags != MAX_NONE) { PlaceMaximizedClient(np, np->state.maxFlags); } ResetBorder(np); event.type = MapRequest; event.xmaprequest.send_event = True; event.xmaprequest.display = display; event.xmaprequest.parent = np->parent; event.xmaprequest.window = np->window; JXSendEvent(display, rootWindow, False, SubstructureRedirectMask, &event); } WriteState(np); SendConfigureEvent(np); RequireRestack(); }
/** Add a window to management. */ ClientNode *AddClientWindow(Window w, char alreadyMapped, char notOwner) { XWindowAttributes attr; ClientNode *np; Assert(w != None); /* Get window attributes. */ if(JXGetWindowAttributes(display, w, &attr) == 0) { return NULL; } /* Determine if we should care about this window. */ if(attr.override_redirect == True) { return NULL; } if(attr.class == InputOnly) { return NULL; } /* Prepare a client node for this window. */ np = Allocate(sizeof(ClientNode)); memset(np, 0, sizeof(ClientNode)); np->window = w; np->owner = None; np->state.desktop = currentDesktop; np->x = attr.x; np->y = attr.y; np->width = attr.width; np->height = attr.height; np->cmap = attr.colormap; np->state.status = STAT_NONE; np->state.maxFlags = MAX_NONE; np->state.layer = LAYER_NORMAL; np->state.defaultLayer = LAYER_NORMAL; np->state.border = BORDER_DEFAULT; np->borderAction = BA_NONE; ReadClientInfo(np, alreadyMapped); if(!notOwner) { np->state.border = BORDER_OUTLINE | BORDER_TITLE | BORDER_MOVE; np->state.status |= STAT_WMDIALOG | STAT_STICKY; np->state.layer = LAYER_ABOVE; np->state.defaultLayer = LAYER_ABOVE; } ApplyGroups(np); if(np->icon == NULL) { LoadIcon(np); } /* We now know the layer, so insert */ np->prev = NULL; np->next = nodes[np->state.layer]; if(np->next) { np->next->prev = np; } else { nodeTail[np->state.layer] = np; } nodes[np->state.layer] = np; SetDefaultCursor(np->window); ReparentClient(np, notOwner); PlaceClient(np, alreadyMapped); if(!((np->state.status & STAT_FULLSCREEN) || np->state.maxFlags)) { int north, south, east, west; GetBorderSize(&np->state, &north, &south, &east, &west); if(np->parent != None) { JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); } else { JXMoveResizeWindow(display, np->window, np->x, np->y, np->width, np->height); } } /* If one of these fails we are SOL, so who cares. */ XSaveContext(display, np->window, clientContext, (void*)np); if(np->parent != None) { XSaveContext(display, np->parent, frameContext, (void*)np); } if(np->state.status & STAT_MAPPED) { JXMapWindow(display, np->window); if(np->parent != None) { JXMapWindow(display, np->parent); } } clientCount += 1; if(!alreadyMapped) { RaiseClient(np); } if(np->state.status & STAT_OPACITY) { SetOpacity(np, np->state.opacity, 1); } else { SetOpacity(np, settings.inactiveClientOpacity, 1); } if(np->state.status & STAT_STICKY) { SetCardinalAtom(np->window, ATOM_NET_WM_DESKTOP, ~0UL); } else { SetCardinalAtom(np->window, ATOM_NET_WM_DESKTOP, np->state.desktop); } /* Shade the client if requested. */ if(np->state.status & STAT_SHADED) { np->state.status &= ~STAT_SHADED; ShadeClient(np); } /* Minimize the client if requested. */ if(np->state.status & STAT_MINIMIZED) { np->state.status &= ~STAT_MINIMIZED; MinimizeClient(np, 0); } /* Maximize the client if requested. */ if(np->state.maxFlags) { const MaxFlags flags = np->state.maxFlags; np->state.maxFlags = MAX_NONE; MaximizeClient(np, flags); } if(np->state.status & STAT_URGENT) { RegisterCallback(URGENCY_DELAY, SignalUrgent, np); } /* Update task bars. */ AddClientToTaskBar(np); /* Make sure we're still in sync */ WriteState(np); SendConfigureEvent(np); /* Hide the client if we're not on the right desktop. */ if(np->state.desktop != currentDesktop && !(np->state.status & STAT_STICKY)) { HideClient(np); } ReadClientStrut(np); /* Focus transients if their parent has focus. */ if(np->owner != None) { if(activeClient && np->owner == activeClient->window) { FocusClient(np); } } /* Make the client fullscreen if requested. */ if(np->state.status & STAT_FULLSCREEN) { np->state.status &= ~STAT_FULLSCREEN; SetClientFullScreen(np, 1); } ResetBorder(np); return np; }
/** Handle a _NET_MOVERESIZE_WINDOW request. */ void HandleNetMoveResize(const XClientMessageEvent *event, ClientNode *np) { long flags, gravity; long x, y; long width, height; int deltax, deltay; int north, south, east, west; Assert(event); Assert(np); gravity = event->data.l[0] & 0xFF; flags = event->data.l[0] >> 8; x = np->x; y = np->y; width = np->width; height = np->height; if(flags & (1 << 0)) { x = event->data.l[1]; } if(flags & (1 << 1)) { y = event->data.l[2]; } if(flags & (1 << 2)) { width = event->data.l[3]; } if(flags & (1 << 3)) { height = event->data.l[4]; } if(gravity == 0) { gravity = np->gravity; } GetBorderSize(np, &north, &south, &east, &west); GetGravityDelta(np, &deltax, &deltay); x -= deltax; y -= deltay; np->x = x; np->y = y; np->width = width; np->height = height; if(np->state.status & STAT_FULLSCREEN) { Warning("Fullscreen state will be shaped!"); } /** Reset shaped bound */ ResetRoundedRectWindow(np->parent); ShapeRoundedRectWindow(np->parent, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); WriteState(np); SendConfigureEvent(np); }
/** Resize a client window (mouse initiated). */ void ResizeClient(ClientNode *np, BorderActionType action, int startx, int starty) { XEvent event; int oldx, oldy; int oldw, oldh; int gwidth, gheight; int lastgwidth, lastgheight; int delta; int north, south, east, west; int ratio, minr, maxr; Assert(np); if(!(np->state.border & BORDER_RESIZE)) { return; } if(JUNLIKELY(!GrabMouseForResize(action))) { Debug("ResizeClient: could not grab mouse"); return; } if(np->state.status & STAT_SHADED) { action &= ~(BA_RESIZE_N | BA_RESIZE_S); } np->controller = ResizeController; shouldStopResize = 0; oldx = np->x; oldy = np->y; oldw = np->width; oldh = np->height; gwidth = (np->width - np->baseWidth) / np->xinc; gheight = (np->height - np->baseHeight) / np->yinc; GetBorderSize(np, &north, &south, &east, &west); startx += np->x - west; starty += np->y - north; CreateResizeWindow(np); UpdateResizeWindow(np, gwidth, gheight); if(!(GetMouseMask() & (Button1Mask | Button3Mask))) { StopResize(np); return; } for(;;) { WaitForEvent(&event); if(shouldStopResize) { np->controller = NULL; return; } switch(event.type) { case ButtonRelease: if( event.xbutton.button == Button1 || event.xbutton.button == Button3) { StopResize(np); return; } break; case MotionNotify: SetMousePosition(event.xmotion.x_root, event.xmotion.y_root); DiscardMotionEvents(&event, np->window); if(action & BA_RESIZE_N) { delta = (event.xmotion.y - starty) / np->yinc; delta *= np->yinc; if(oldh - delta >= np->minHeight && (oldh - delta <= np->maxHeight || delta > 0)) { np->height = oldh - delta; np->y = oldy + delta; } if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { FixWidth(np); } } if(action & BA_RESIZE_S) { delta = (event.xmotion.y - starty) / np->yinc; delta *= np->yinc; np->height = oldh + delta; np->height = Max(np->height, np->minHeight); np->height = Min(np->height, np->maxHeight); if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { FixWidth(np); } } if(action & BA_RESIZE_E) { delta = (event.xmotion.x - startx) / np->xinc; delta *= np->xinc; np->width = oldw + delta; np->width = Max(np->width, np->minWidth); np->width = Min(np->width, np->maxWidth); if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { FixHeight(np); } } if(action & BA_RESIZE_W) { delta = (event.xmotion.x - startx) / np->xinc; delta *= np->xinc; if(oldw - delta >= np->minWidth && (oldw - delta <= np->maxWidth || delta > 0)) { np->width = oldw - delta; np->x = oldx + delta; } if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { FixHeight(np); } } if(np->sizeFlags & PAspect) { if((action & (BA_RESIZE_N | BA_RESIZE_S)) && (action & (BA_RESIZE_E | BA_RESIZE_W))) { /* Fixed point with a 16-bit fraction. */ ratio = (np->width << 16) / np->height; minr = (np->aspect.minx << 16) / np->aspect.miny; if(ratio < minr) { delta = np->width; np->width = (np->height * minr) >> 16; if(action & BA_RESIZE_W) { np->x -= np->width - delta; } } maxr = (np->aspect.maxx << 16) / np->aspect.maxy; if(ratio > maxr) { delta = np->height; np->height = (np->width << 16) / maxr; if(action & BA_RESIZE_N) { np->y -= np->height - delta; } } } } lastgwidth = gwidth; lastgheight = gheight; gwidth = (np->width - np->baseWidth) / np->xinc; gheight = (np->height - np->baseHeight) / np->yinc; if(lastgheight != gheight || lastgwidth != gwidth) { if(np->state.status & (STAT_HMAX | STAT_VMAX)) { np->state.status &= ~(STAT_HMAX | STAT_VMAX); WriteState(np); SendConfigureEvent(np); } UpdateResizeWindow(np, gwidth, gheight); if(resizeMode == RESIZE_OUTLINE) { ClearOutline(); if(np->state.status & STAT_SHADED) { DrawOutline(np->x - west, np->y - north, np->width + west + east, north + south); } else { DrawOutline(np->x - west, np->y - north, np->width + west + east, np->height + north + south); } } else { ResetRoundedRectWindow(np->parent); if(np->state.status & STAT_SHADED) { ShapeRoundedRectWindow(np->parent, np->width + east + west, north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + west + east, north + south); } else { ShapeRoundedRectWindow(np->parent, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + west + east, np->height + north + south); } JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); SendConfigureEvent(np); } UpdatePager(); } break; default: break; }