/** Process a button event. */ void HandleButtonEvent(const XButtonEvent *event) { ClientNode *np; int north, south, east, west; np = FindClientByParent(event->window); if(np) { if(event->type == ButtonPress) { FocusClient(np); RaiseClient(np); } DispatchBorderButtonEvent(event, np); } else if(event->window == rootWindow && event->type == ButtonPress) { if(!ShowRootMenu(event->button, event->x, event->y, 0)) { if(event->button == Button4) { LeftDesktop(); } else if(event->button == Button5) { RightDesktop(); } } } else { const unsigned int mask = event->state & ~lockMask; np = FindClientByWindow(event->window); if(np) { switch(event->button) { case Button1: case Button2: FocusClient(np); RaiseClient(np); if(mask == Mod1Mask) { GetBorderSize(&np->state, &north, &south, &east, &west); MoveClient(np, event->x + west, event->y + north); } break; case Button3: if(mask == Mod1Mask) { GetBorderSize(&np->state, &north, &south, &east, &west); ResizeClient(np, BA_RESIZE | BA_RESIZE_E | BA_RESIZE_S, event->x + west, event->y + north); } else { FocusClient(np); RaiseClient(np); } break; default: break; } JXAllowEvents(display, ReplayPointer, eventTime); } } }
/** Stop walking the window stack or client list. */ void StopWindowWalk(void) { ClientNode *np; /* Raise the selected window and free the window array. */ if(windowStack != NULL) { /* Look up the current window. */ np = FindClientByWindow(windowStack[windowStackCurrent]); if(np) { if(np->state.status & STAT_MINIMIZED) { RestoreClient(np, 1); } else { RaiseClient(np); } } Release(windowStack); windowStack = NULL; windowStackSize = 0; windowStackCurrent = 0; } if(walkingWindows) { JXUngrabKeyboard(display, CurrentTime); LowerTrays(); walkingWindows = 0; } }
/** Restore a window with its transients (helper method). */ void RestoreTransients(ClientNode *np, char raise) { ClientNode *tp; int x; Assert(np); /* Make sure this window is on the current desktop. */ SetClientDesktop(np, currentDesktop); /* Restore this window. */ if(!(np->state.status & STAT_MAPPED)) { if(np->state.status & STAT_SHADED) { if(np->parent != None) { JXMapWindow(display, np->parent); } } else { JXMapWindow(display, np->window); if(np->parent != None) { JXMapWindow(display, np->parent); } np->state.status |= STAT_MAPPED; } } np->state.status &= ~STAT_MINIMIZED; np->state.status &= ~STAT_SDESKTOP; /* Restore transient windows. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp->owner == np->window && (tp->state.status & STAT_MINIMIZED)) { RestoreTransients(tp, raise); } } } if(raise) { FocusClient(np); RaiseClient(np); } WriteState(np); }
/** Handle a map request. */ void HandleMapRequest(const XMapEvent *event) { ClientNode *np; Assert(event); if(CheckSwallowMap(event)) { return; } np = FindClientByWindow(event->window); if(!np) { JXSync(display, False); JXGrabServer(display); np = AddClientWindow(event->window, 0, 1); if(np) { if(focusModel == FOCUS_CLICK && !(np->state.status & STAT_NOFOCUS)) { FocusClient(np); } } else { JXMapWindow(display, event->window); } JXSync(display, False); JXUngrabServer(display); } else { if(!(np->state.status & STAT_MAPPED)) { np->state = ReadWindowState(np->window); np->state.status |= STAT_MAPPED; if(!(np->state.status & STAT_STICKY)) { np->state.desktop = currentDesktop; } JXMapWindow(display, np->window); JXMapWindow(display, np->parent); if(!(np->state.status & STAT_NOFOCUS)) { RaiseClient(np); FocusClient(np); } UpdateTaskBar(); UpdatePager(); } } RestackClients(); }
/** 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(); }
/** Handle a map request. */ void HandleMapRequest(const XMapEvent *event) { ClientNode *np; Assert(event); if(CheckSwallowMap(event->window)) { return; } np = FindClientByWindow(event->window); if(!np) { GrabServer(); np = AddClientWindow(event->window, 0, 1); if(np) { if(!(np->state.status & STAT_NOFOCUS)) { FocusClient(np); } } else { JXMapWindow(display, event->window); } UngrabServer(); } else { if(!(np->state.status & STAT_MAPPED)) { UpdateState(np); np->state.status |= STAT_MAPPED; XMapWindow(display, np->window); if(np->parent != None) { XMapWindow(display, np->parent); } if(!(np->state.status & STAT_STICKY)) { np->state.desktop = currentDesktop; } if(!(np->state.status & STAT_NOFOCUS)) { FocusClient(np); RaiseClient(np); } WriteState(np); RequireTaskUpdate(); RequirePagerUpdate(); } } RequireRestack(); }
/** Process a key press event. */ void HandleKeyPress(const XKeyEvent *event) { ClientNode *np; KeyType key; SetMousePosition(event->x_root, event->y_root, event->window); key = GetKey(event); np = GetActiveClient(); switch(key & 0xFF) { case KEY_EXEC: RunKeyCommand(event); break; case KEY_DESKTOP: ChangeDesktop((key >> 8) - 1); break; case KEY_RDESKTOP: RightDesktop(); break; case KEY_LDESKTOP: LeftDesktop(); break; case KEY_UDESKTOP: AboveDesktop(); break; case KEY_DDESKTOP: BelowDesktop(); break; case KEY_SHOWDESK: ShowDesktop(); break; case KEY_SHOWTRAY: ShowAllTrays(); break; case KEY_NEXT: StartWindowWalk(); FocusNext(); break; case KEY_NEXTSTACK: StartWindowStackWalk(); WalkWindowStack(1); break; case KEY_PREV: StartWindowWalk(); FocusPrevious(); break; case KEY_PREVSTACK: StartWindowStackWalk(); WalkWindowStack(0); break; case KEY_CLOSE: if(np) { DeleteClient(np); } break; case KEY_SHADE: if(np) { if(np->state.status & STAT_SHADED) { UnshadeClient(np); } else { ShadeClient(np); } } break; case KEY_STICK: if(np) { if(np->state.status & STAT_STICKY) { SetClientSticky(np, 0); } else { SetClientSticky(np, 1); } } break; case KEY_MOVE: if(np) { MoveClientKeyboard(np); } break; case KEY_RESIZE: if(np) { ResizeClientKeyboard(np); } break; case KEY_MIN: if(np) { MinimizeClient(np, 1); } break; case KEY_MAX: if(np) { if(np->state.maxFlags) { MaximizeClient(np, MAX_NONE); } else { MaximizeClient(np, MAX_HORIZ | MAX_VERT); } } break; case KEY_MAXTOP: ToggleMaximized(np, MAX_TOP | MAX_HORIZ); break; case KEY_MAXBOTTOM: ToggleMaximized(np, MAX_BOTTOM | MAX_HORIZ); break; case KEY_MAXLEFT: ToggleMaximized(np, MAX_LEFT | MAX_VERT); break; case KEY_MAXRIGHT: ToggleMaximized(np, MAX_RIGHT | MAX_VERT); break; case KEY_MAXV: ToggleMaximized(np, MAX_VERT); break; case KEY_MAXH: ToggleMaximized(np, MAX_HORIZ); break; case KEY_ROOT: ShowKeyMenu(event); break; case KEY_WIN: if(np) { RaiseClient(np); ShowWindowMenu(np, np->x, np->y, 1); } break; case KEY_RESTART: Restart(); break; case KEY_EXIT: Exit(); break; case KEY_FULLSCREEN: if(np) { if(np->state.status & STAT_FULLSCREEN) { SetClientFullScreen(np, 0); } else { SetClientFullScreen(np, 1); } } break; case KEY_SENDR: if(np) { SetClientDesktop(np, GetRightDesktop(np->state.desktop)); } break; case KEY_SENDL: if(np) { SetClientDesktop(np, GetLeftDesktop(np->state.desktop)); } break; case KEY_SENDU: if(np) { SetClientDesktop(np, GetAboveDesktop(np->state.desktop)); } break; case KEY_SENDD: if(np) { SetClientDesktop(np, GetBelowDesktop(np->state.desktop)); } break; default: break; } DiscardEnterEvents(); }
/** 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; }
/** Process a button event. */ void HandleButtonEvent(const XButtonEvent *event) { int x, y; ClientNode *np; int north, south, east, west; np = FindClientByParent(event->window); if(np) { RaiseClient(np); if(focusModel == FOCUS_CLICK) { FocusClient(np); } switch(event->button) { case Button1: DispatchBorderButtonEvent(event, np); break; case Button2: MoveClient(np, event->x, event->y); break; case Button3: GetBorderSize(np, &north, &south, &east, &west); x = event->x + np->x - west; y = event->y + np->y - north; ShowWindowMenu(np, x, y); break; case Button4: ShadeClient(np); break; case Button5: UnshadeClient(np); break; default: break; } } else if(event->window == rootWindow && event->type == ButtonPress) { if(!ShowRootMenu(event->button, event->x, event->y)) { if(event->button == 4) { LeftDesktop(); } else if(event->button == 5) { RightDesktop(); } } } else { np = FindClientByWindow(event->window); if(np) { switch(event->button) { case Button1: case Button2: RaiseClient(np); if(focusModel == FOCUS_CLICK) { FocusClient(np); } if(event->state & Mod1Mask) { GetBorderSize(np, &north, &south, &east, &west); MoveClient(np, event->x + west, event->y + north); } break; case Button3: if(event->state & Mod1Mask) { GetBorderSize(np, &north, &south, &east, &west); ResizeClient(np, BA_RESIZE | BA_RESIZE_E | BA_RESIZE_S, event->x + west, event->y + north); } else { RaiseClient(np); if(focusModel == FOCUS_CLICK) { FocusClient(np); } } break; default: break; } JXAllowEvents(display, ReplayPointer, CurrentTime); } } UpdatePager(); }