/** Change to the desktop to the left. */ int LeftDesktop() { if(desktopCount > 1) { if(currentDesktop > 0) { ChangeDesktop(currentDesktop - 1); } else { ChangeDesktop(desktopCount - 1); } return 1; } else { return 0; } }
/** Change to the desktop above. */ int AboveDesktop() { if(desktopWidth > 1) { if(currentDesktop >= desktopWidth) { ChangeDesktop(currentDesktop - desktopWidth); } else { ChangeDesktop(currentDesktop + (desktopHeight - 1) * desktopWidth); } return 1; } else { return 0; } }
/** Change to the desktop to the right. */ int RightDesktop() { if(desktopCount > 1) { ChangeDesktop((currentDesktop + 1) % desktopCount); return 1; } else { return 0; } }
/** Change to the desktop below. */ int BelowDesktop() { if(desktopWidth > 1) { ChangeDesktop((currentDesktop + desktopWidth) % desktopCount); return 1; } else { return 0; } }
/** Determine the current desktop. */ void ReadCurrentDesktop(void) { unsigned long temp; currentDesktop = 0; if(GetCardinalAtom(rootWindow, ATOM_NET_CURRENT_DESKTOP, &temp)) { ChangeDesktop(temp); } else { SetCardinalAtom(rootWindow, ATOM_NET_CURRENT_DESKTOP, currentDesktop); } }
/** Change to the desktop to the right. */ int RightDesktop() { int x, y; if(desktopWidth > 1) { y = currentDesktop / desktopWidth; x = (currentDesktop + 1) % desktopWidth; ChangeDesktop(y * desktopWidth + x); return 1; } else { return 0; } }
/** Change to the desktop to the left. */ int LeftDesktop() { int x, y; if(desktopWidth > 1) { y = currentDesktop / desktopWidth; x = currentDesktop % desktopWidth; x = x > 0 ? x - 1 : desktopWidth - 1; ChangeDesktop(y * desktopWidth + x); return 1; } else { return 0; } }
/** Root menu callback. */ void RunRootCommand(const MenuAction *action) { switch(action->type) { case MA_EXECUTE: RunCommand(action->data.str); break; case MA_RESTART: Restart(); break; case MA_EXIT: if(exitCommand) { Release(exitCommand); } exitCommand = CopyString(action->data.str); Exit(); break; case MA_DESKTOP: ChangeDesktop(action->data.i); break; case MA_SENDTO: case MA_LAYER: case MA_MAXIMIZE: case MA_MINIMIZE: case MA_RESTORE: case MA_SHADE: case MA_MOVE: case MA_RESIZE: case MA_KILL: case MA_CLOSE: ChooseWindow(action); break; default: Debug("invalid RunRootCommand action: %d", action->type); break; } }
/** Root menu callback. */ void RunRootCommand(MenuAction *action, unsigned button) { switch(action->type) { case MA_EXECUTE: RunCommand(action->str); break; case MA_RESTART: Restart(); break; case MA_EXIT: if(exitCommand) { Release(exitCommand); } exitCommand = CopyString(action->str); Exit(); break; case MA_DESKTOP: ChangeDesktop(action->value); break; case MA_SENDTO: case MA_LAYER: case MA_MAXIMIZE: case MA_MINIMIZE: case MA_RESTORE: case MA_SHADE: case MA_MOVE: case MA_RESIZE: case MA_KILL: case MA_CLOSE: ChooseWindow(action); break; default: break; } }
/** Raise all clients in a group and focus the top-most. */ void FocusGroup(const TaskEntry *tp) { const char *className = tp->clients->client->className; ClientNode **toRestore; const ClientEntry *cp; unsigned restoreCount; int i; char shouldSwitch; /* If there is no class name, then there will only be one client. */ if(!className || !settings.groupTasks) { if(!(tp->clients->client->state.status & STAT_STICKY)) { ChangeDesktop(tp->clients->client->state.desktop); } RestoreClient(tp->clients->client, 1); FocusClient(tp->clients->client); return; } /* If there is a client in the group on this desktop, * then we remain on the same desktop. */ shouldSwitch = 1; for(cp = tp->clients; cp; cp = cp->next) { if(IsClientOnCurrentDesktop(cp->client)) { shouldSwitch = 0; break; } } /* Switch to the desktop of the top-most client in the group. */ if(shouldSwitch) { for(i = 0; i < LAYER_COUNT; i++) { ClientNode *np; for(np = nodes[i]; np; np = np->next) { if(np->className && !strcmp(np->className, className)) { if(ShouldFocus(np, 0)) { if(!(np->state.status & STAT_STICKY)) { ChangeDesktop(np->state.desktop); } break; } } } } } /* Build up the list of clients to restore in correct order. */ toRestore = AllocateStack(sizeof(ClientNode*) * clientCount); restoreCount = 0; for(i = 0; i < LAYER_COUNT; i++) { ClientNode *np; for(np = nodes[i]; np; np = np->next) { if(!ShouldFocus(np, 1)) { continue; } if(np->className && !strcmp(np->className, className)) { toRestore[restoreCount] = np; restoreCount += 1; } } } Assert(restoreCount <= clientCount); for(i = restoreCount - 1; i >= 0; i--) { RestoreClient(toRestore[i], 1); } for(i = 0; i < restoreCount; i++) { if(toRestore[i]->state.status & (STAT_CANFOCUS | STAT_TAKEFOCUS)) { FocusClient(toRestore[i]); break; } } ReleaseStack(toRestore); }
/** Process a task list button event. */ void ProcessTaskButtonEvent(TrayComponentType *cp, int x, int y, int mask) { TaskBarType *bar = (TaskBarType*)cp->object; TaskEntry *entry = GetEntry(bar, x, y); if(entry) { ClientEntry *cp; ClientNode *focused = NULL; char onTop = 0; char hasActive = 0; switch(mask) { case Button1: /* Raise or minimize items in this group. */ for(cp = entry->clients; cp; cp = cp->next) { int layer; char foundTop = 0; if(cp->client->state.status & STAT_MINIMIZED) { continue; } else if(!ShouldFocus(cp->client, 0)) { continue; } for(layer = LAST_LAYER; layer >= FIRST_LAYER; layer--) { ClientNode *np; for(np = nodes[layer]; np; np = np->next) { if(np->state.status & STAT_MINIMIZED) { continue; } else if(!ShouldFocus(np, 0)) { continue; } if(np == cp->client) { const char isActive = (np->state.status & STAT_ACTIVE) && IsClientOnCurrentDesktop(np); onTop = onTop || !foundTop; if(isActive) { focused = np; } if(!(cp->client->state.status & (STAT_CANFOCUS | STAT_TAKEFOCUS)) || isActive) { hasActive = 1; } } if(hasActive && onTop) { goto FoundActiveAndTop; } foundTop = 1; } } } FoundActiveAndTop: if(hasActive && onTop) { ClientNode *nextClient = NULL; int i; /* Try to find a client on a different desktop. */ for(i = 0; i < settings.desktopCount - 1; i++) { const int target = (currentDesktop + i + 1) % settings.desktopCount; for(cp = entry->clients; cp; cp = cp->next) { ClientNode *np = cp->client; if(!ShouldFocus(np, 0)) { continue; } else if(np->state.status & STAT_STICKY) { continue; } else if(np->state.desktop == target) { if(!nextClient || np->state.status & STAT_ACTIVE) { nextClient = np; } } } if(nextClient) { break; } } /* Focus the next client or minimize the current group. */ if(nextClient) { ChangeDesktop(nextClient->state.desktop); RestoreClient(nextClient, 1); } else { MinimizeGroup(entry); } } else { FocusGroup(entry); if(focused) { FocusClient(focused); } } break; case Button3: ShowClientList(bar, entry); break; case Button4: FocusPrevious(); break; case Button5: FocusNext(); break; default: break; } } }
/** Handle a client message. */ void HandleClientMessage(const XClientMessageEvent *event) { ClientNode *np; #ifdef DEBUG char *atomName; #endif np = FindClientByWindow(event->window); if(np) { if(event->message_type == atoms[ATOM_WM_CHANGE_STATE]) { if(np->controller) { (np->controller)(0); } switch(event->data.l[0]) { case WithdrawnState: SetClientWithdrawn(np); break; case IconicState: MinimizeClient(np, 1); break; case NormalState: RestoreClient(np, 1); break; default: break; } } else if(event->message_type == atoms[ATOM_NET_ACTIVE_WINDOW]) { RestoreClient(np, 1); UnshadeClient(np); FocusClient(np); } else if(event->message_type == atoms[ATOM_NET_WM_DESKTOP]) { if(event->data.l[0] == ~0L) { SetClientSticky(np, 1); } else { if(np->controller) { (np->controller)(0); } if( event->data.l[0] >= 0 && event->data.l[0] < (long)settings.desktopCount) { np->state.status &= ~STAT_STICKY; SetClientDesktop(np, event->data.l[0]); } } } else if(event->message_type == atoms[ATOM_NET_CLOSE_WINDOW]) { DeleteClient(np); } else if(event->message_type == atoms[ATOM_NET_MOVERESIZE_WINDOW]) { HandleNetMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_MOVERESIZE]) { HandleNetWMMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_RESTACK_WINDOW]) { HandleNetRestack(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_STATE]) { HandleNetWMState(event, np); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to client: %s", atomName); JXFree(atomName); #endif } } else if(event->window == rootWindow) { if(event->message_type == atoms[ATOM_JWM_RESTART]) { Restart(); } else if(event->message_type == atoms[ATOM_JWM_EXIT]) { Exit(); } else if(event->message_type == atoms[ATOM_JWM_RELOAD]) { ReloadMenu(); } else if(event->message_type == atoms[ATOM_NET_CURRENT_DESKTOP]) { ChangeDesktop(event->data.l[0]); } else if(event->message_type == atoms[ATOM_NET_SHOWING_DESKTOP]) { ShowDesktop(); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to root: %s", atomName); JXFree(atomName); #endif } } else if(event->message_type == atoms[ATOM_NET_REQUEST_FRAME_EXTENTS]) { HandleFrameExtentsRequest(event); } else if(event->message_type == atoms[ATOM_NET_SYSTEM_TRAY_OPCODE]) { HandleDockEvent(event); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("ClientMessage to unknown window (0x%x): %s", event->window, atomName); JXFree(atomName); #endif } }
/** Handle a client message. */ void HandleClientMessage(const XClientMessageEvent *event) { ClientNode *np; long mask, flags; #ifdef DEBUG char *atomName; #endif np = FindClientByWindow(event->window); if(np) { if(event->message_type == atoms[ATOM_WIN_STATE]) { mask = event->data.l[0]; flags = event->data.l[1]; if(mask & WIN_STATE_STICKY) { if(flags & WIN_STATE_STICKY) { SetClientSticky(np, 1); } else { SetClientSticky(np, 0); } } if(mask & WIN_STATE_HIDDEN) { if(flags & WIN_STATE_HIDDEN) { np->state.status |= STAT_NOLIST; } else { np->state.status &= ~STAT_NOLIST; } UpdateTaskBar(); UpdatePager(); } } else if(event->message_type == atoms[ATOM_WIN_LAYER]) { SetClientLayer(np, event->data.l[0]); } else if(event->message_type == atoms[ATOM_WM_CHANGE_STATE]) { if(np->controller) { (np->controller)(0); } switch(event->data.l[0]) { case WithdrawnState: SetClientWithdrawn(np); break; case IconicState: MinimizeClient(np); break; case NormalState: RestoreClient(np, 1); break; default: break; } } else if(event->message_type == atoms[ATOM_NET_ACTIVE_WINDOW]) { RestoreClient(np, 1); FocusClient(np); } else if(event->message_type == atoms[ATOM_NET_WM_DESKTOP]) { if(event->data.l[0] == ~0L) { SetClientSticky(np, 1); } else { if(np->controller) { (np->controller)(0); } if(event->data.l[0] >= 0 && event->data.l[0] < (long)desktopCount) { np->state.status &= ~STAT_STICKY; SetClientDesktop(np, event->data.l[0]); } } } else if(event->message_type == atoms[ATOM_NET_CLOSE_WINDOW]) { DeleteClient(np); } else if(event->message_type == atoms[ATOM_NET_MOVERESIZE_WINDOW]) { HandleNetMoveResize(event, np); } else if(event->message_type == atoms[ATOM_NET_WM_STATE]) { HandleNetWMState(event, np); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to client: %s", atomName); JXFree(atomName); #endif } } else if(event->window == rootWindow) { if(event->message_type == atoms[ATOM_JWM_RESTART]) { Restart(); } else if(event->message_type == atoms[ATOM_JWM_EXIT]) { Exit(); } else if(event->message_type == atoms[ATOM_NET_CURRENT_DESKTOP]) { ChangeDesktop(event->data.l[0]); } else { #ifdef DEBUG atomName = JXGetAtomName(display, event->message_type); Debug("Unknown ClientMessage to root: %s", atomName); JXFree(atomName); #endif } } else if(event->message_type == atoms[ATOM_NET_SYSTEM_TRAY_OPCODE]) { HandleDockEvent(event); } }