/** Switch desktops if appropriate. */ void SignalMove(const TimeType *now, int x, int y, Window w, void *data) { if(settings.desktopDelay == 0) { return; } if(GetTimeDifference(now, &moveTime) < settings.desktopDelay) { return; } moveTime = *now; if(atLeft && LeftDesktop()) { SetClientDesktop(currentClient, currentDesktop); RestackClients(); } else if(atRight && RightDesktop()) { SetClientDesktop(currentClient, currentDesktop); RestackClients(); } else if(atTop && AboveDesktop()) { SetClientDesktop(currentClient, currentDesktop); RestackClients(); } else if(atBottom && BelowDesktop()) { SetClientDesktop(currentClient, currentDesktop); RestackClients(); } }
/** Set a client's sticky status. This will update transients. */ void SetClientSticky(ClientNode *np, char isSticky) { ClientNode *tp; int x; char old; Assert(np); /* Get the old sticky status. */ if(np->state.status & STAT_STICKY) { old = 1; } else { old = 0; } if(isSticky && !old) { /* Change from non-sticky to sticky. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp == np || tp->owner == np->window) { tp->state.status |= STAT_STICKY; SetCardinalAtom(tp->window, ATOM_NET_WM_DESKTOP, ~0UL); WriteState(tp); } } } } else if(!isSticky && old) { /* Change from sticky to non-sticky. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp == np || tp->owner == np->window) { tp->state.status &= ~STAT_STICKY; WriteState(tp); } } } /* Since this client is no longer sticky, we need to assign * a desktop. Here we use the current desktop. * Note that SetClientDesktop updates transients (which is good). */ SetClientDesktop(np, currentDesktop); } }
/** Switch to the specified desktop. */ void UpdateDesktop(const TimeType *now) { if(settings.desktopDelay == 0) { return; } if(GetTimeDifference(now, &moveTime) < settings.desktopDelay) { return; } moveTime = *now; if(atLeft && LeftDesktop()) { SetClientDesktop(currentClient, currentDesktop); RequireRestack(); } else if(atRight && RightDesktop()) { SetClientDesktop(currentClient, currentDesktop); RequireRestack(); } else if(atTop && AboveDesktop()) { SetClientDesktop(currentClient, currentDesktop); RequireRestack(); } else if(atBottom && BelowDesktop()) { SetClientDesktop(currentClient, currentDesktop); RequireRestack(); } }
/** 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); }
/** Run a menu action. */ void RunTaskBarCommand(MenuAction *action, unsigned button) { ClientEntry *cp; if(action->type & MA_GROUP_MASK) { TaskEntry *tp = action->context; for(cp = tp->clients; cp; cp = cp->next) { if(!ShouldFocus(cp->client, 0)) { continue; } switch(action->type & ~MA_GROUP_MASK) { case MA_SENDTO: SetClientDesktop(cp->client, action->value); break; case MA_CLOSE: DeleteClient(cp->client); break; case MA_RESTORE: RestoreClient(cp->client, 0); break; case MA_MINIMIZE: MinimizeClient(cp->client, 0); break; default: break; } } } else if(action->type == MA_EXECUTE) { if(button == Button3) { Window w; int x, y; GetMousePosition(&x, &y, &w); ShowWindowMenu(action->context, x, y, 0); } else { ClientNode *np = action->context; RestoreClient(np, 1); FocusClient(np); MoveMouse(np->window, np->width / 2, np->height / 2); } } else { RunWindowCommand(action, button); } }
/** Window menu action callback. */ void RunWindowCommand(const MenuAction *action) { switch(action->type) { case MA_STICK: if(client->state.status & STAT_STICKY) { SetClientSticky(client, 0); } else { SetClientSticky(client, 1); } break; case MA_MAXIMIZE: if(client->state.maxFlags) { MaximizeClient(client, MAX_NONE); } else { MaximizeClient(client, MAX_VERT | MAX_HORIZ); } break; case MA_MAXIMIZE_H: MaximizeClient(client, MAX_HORIZ); break; case MA_MAXIMIZE_V: MaximizeClient(client, MAX_VERT); break; case MA_MINIMIZE: MinimizeClient(client, 1); break; case MA_RESTORE: RestoreClient(client, 1); break; case MA_CLOSE: DeleteClient(client); break; case MA_SENDTO: case MA_DESKTOP: SetClientDesktop(client, action->data.i); break; case MA_SHADE: if(client->state.status & STAT_SHADED) { UnshadeClient(client); } else { ShadeClient(client); } break; case MA_MOVE: MoveClientKeyboard(client); break; case MA_RESIZE: ResizeClientKeyboard(client); break; case MA_KILL: KillClient(client); break; case MA_LAYER: SetClientLayer(client, action->data.i); break; default: Debug("unknown window command: %d", action->type); break; } }
/** Window menu action callback. */ void RunWindowCommand(MenuAction *action, unsigned button) { ClientNode *client = action->context; switch(action->type) { case MA_STICK: if(client->state.status & STAT_STICKY) { SetClientSticky(client, 0); } else { SetClientSticky(client, 1); } break; case MA_MAXIMIZE: if((client->state.maxFlags & MAX_HORIZ) && (client->state.maxFlags & MAX_VERT) && !(client->state.status & STAT_MINIMIZED)) { MaximizeClient(client, MAX_NONE); } else { MaximizeClient(client, MAX_VERT | MAX_HORIZ); } break; case MA_MAXIMIZE_H: if((client->state.maxFlags & MAX_HORIZ) && !(client->state.maxFlags & MAX_VERT) && !(client->state.status & STAT_MINIMIZED)) { MaximizeClient(client, MAX_NONE); } else { MaximizeClient(client, MAX_HORIZ); } break; case MA_MAXIMIZE_V: if((client->state.maxFlags & MAX_VERT) && !(client->state.maxFlags & MAX_HORIZ) && !(client->state.status & STAT_MINIMIZED)) { MaximizeClient(client, MAX_NONE); } else { MaximizeClient(client, MAX_VERT); } break; case MA_MINIMIZE: MinimizeClient(client, 1); break; case MA_RESTORE: RestoreClient(client, 1); break; case MA_CLOSE: DeleteClient(client); break; case MA_SENDTO: case MA_DESKTOP: SetClientDesktop(client, action->value); break; case MA_SHADE: if(client->state.status & STAT_SHADED) { UnshadeClient(client); } else { ShadeClient(client); } break; case MA_MOVE: MoveClientKeyboard(client); break; case MA_RESIZE: ResizeClientKeyboard(client); break; case MA_KILL: KillClient(client); break; case MA_LAYER: SetClientLayer(client, action->value); 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 } }
/** 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(); }
/** Process a key press event. */ void HandleKeyPress(const XKeyEvent *event) { ClientNode *np; KeyType key; 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) { MaximizeClient(np, 1, 1); } break; case KEY_ROOT: ShowKeyMenu(event); break; case KEY_WIN: if(np) { ShowWindowMenu(np, np->x, np->y); } 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; } }
/** 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); } }