/* * \/\/\ * * Copyright (C) 2012-2018 Vito Caputo - * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /* contexts (this is derived from desktops) */ #include #include #include #include #include "list.h" #include "context.h" #include "desktop.h" #include "vwm.h" #include "xwindow.h" /* make the specified context the most recently used one */ vwm_context_t * vwm_context_mru(vwm_t *vwm, vwm_context_t *context) { VWM_TRACE("MRU context: %p", context); list_move(&context->contexts_mru, &vwm->contexts_mru); return context; } /* return next MRU context relative to the supplied context */ vwm_context_t * vwm_context_next_mru(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction) { list_head_t *next; switch (direction) { case VWM_DIRECTION_FORWARD: if (context->contexts_mru.next == &vwm->contexts_mru) { next = context->contexts_mru.next->next; } else { next = context->contexts_mru.next; } break; case VWM_DIRECTION_REVERSE: if (context->contexts_mru.prev == &vwm->contexts_mru) { next = context->contexts_mru.prev->prev; } else { next = context->contexts_mru.prev; } break; default: assert(0); } return list_entry(next, vwm_context_t, contexts_mru); } /* return next context spatially relative to the supplied context, no wrap-around */ vwm_context_t * vwm_context_next(vwm_t *vwm, vwm_context_t *context, vwm_direction_t direction) { switch (direction) { case VWM_DIRECTION_FORWARD: if (context->contexts.next != &vwm->contexts) context = list_entry(context->contexts.next, vwm_context_t, contexts); break; case VWM_DIRECTION_REVERSE: if (context->contexts.prev != &vwm->contexts) context = list_entry(context->contexts.prev, vwm_context_t, contexts); break; } return context; } /* helper for automatically assigning context colors */ static int next_context_color_idx(vwm_t *vwm) { int counts[VWM_CONTEXT_COLOR_MAX] = {}; vwm_context_t *context; int color = 0; /* TODO: contexts should probably keep a window count, * so this could skip empty contexts, then those * would be automatically recycled. */ list_for_each_entry(context, &vwm->contexts, contexts) counts[context->color]++; for (int i = 0; i < NELEMS(counts); i++) { if (counts[i] < counts[color]) color = i; } return color; } /* create a context */ /* if color = -1 one is automatically assigned, * otherwise the supplied color is used. */ vwm_context_t * vwm_context_create(vwm_t *vwm, int color, vwm_desktop_t *desktop) { vwm_context_t *context; context = calloc(1, sizeof(vwm_context_t)); if (context == NULL) { VWM_PERROR("Failed to allocate context"); goto _fail; } if (color < 0) color = next_context_color_idx(vwm); assert(color < NELEMS(vwm->context_colors)); context->color = color; list_add_tail(&context->contexts, &vwm->contexts); list_add_tail(&context->contexts_mru, &vwm->contexts_mru); if (!desktop) desktop = vwm_desktop_create(vwm, context); context->focused_desktop = desktop; return context; _fail: return NULL; } /* destroy a context */ void vwm_context_destroy(vwm_t *vwm, vwm_context_t *context) { /* silently refuse to destroy a context having windows (for now) */ /* there's _always_ a focused window on a context having mapped windows */ if (context->focused_desktop && context->focused_desktop->focused_window) return; /* also silently refuse to destroy the last context (for now) */ if (context->contexts.next == context->contexts.prev) return; list_del(&context->contexts); list_del(&context->contexts_mru); } /* find a context by color, creating one if needed */ vwm_context_t * vwm_context_by_color(vwm_t *vwm, unsigned color) { vwm_context_t *context; list_for_each_entry(context, &vwm->contexts, contexts) { if (context->color == color) return context; } return vwm_context_create(vwm, color, NULL); }