Exemple #1
0
/** Start walking the window stack. */
void StartWindowStackWalk(void)
{

   /* Get an image of the window stack.
    * Here we get the Window IDs rather than client pointers so
    * clients can be added/removed without disrupting the stack walk.
    */

   ClientNode *np;
   int layer;
   int count;

   /* If we are already walking the stack, just return. */
   if(windowStack != NULL) {
      return;
   }

   /* First determine how much space to allocate for windows. */
   count = 0;
   for(layer = LAST_LAYER; layer >= FIRST_LAYER; layer--) {
      for(np = nodes[layer]; np; np = np->next) {
         if(ShouldFocus(np, 1)) {
            ++count;
         }
      }
   }

   /* If there were no windows to walk, don't even start. */
   if(count == 0) {
      return;
   }

   /* Allocate space for the windows. */
   windowStack = Allocate(sizeof(Window) * count);

   /* Copy windows into the array. */
   windowStackSize = 0;
   for(layer = LAST_LAYER; layer >= FIRST_LAYER; layer--) {
      for(np = nodes[layer]; np; np = np->next) {
         if(ShouldFocus(np, 1)) {
            windowStack[windowStackSize++] = np->window;
         }
      }
   }

   Assert(windowStackSize == count);

   windowStackCurrent = 0;

   JXGrabKeyboard(display, rootWindow, False, GrabModeAsync,
                  GrabModeAsync, CurrentTime);

   RaiseTrays();

   walkingWindows = 1;
   wasMinimized = 0;

}
Exemple #2
0
/** Minimize all clients in a group. */
void MinimizeGroup(const TaskEntry *tp)
{
   ClientEntry *cp;
   for(cp = tp->clients; cp; cp = cp->next) {
      if(ShouldFocus(cp->client, 1)) {
         MinimizeClient(cp->client, 0);
      }
   }
}
Exemple #3
0
/** Move to the next window in the window stack. */
void WalkWindowStack(char forward)
{

   ClientNode *np;

   if(windowStack != NULL) {
      int x;

      if(wasMinimized) {
         np = FindClientByWindow(windowStack[windowStackCurrent]);
         if(np) {
            MinimizeClient(np, 1);
         }
      }

      /* Loop until we either raise a window or go through them all. */
      for(x = 0; x < windowStackSize; x++) {

         /* Move to the next/previous window (wrap if needed). */
         if(forward) {
             windowStackCurrent = (windowStackCurrent + 1) % windowStackSize;
         } else {
             if(windowStackCurrent == 0) {
                 windowStackCurrent = windowStackSize;
             }
             windowStackCurrent -= 1;
         }

         /* Look up the window. */
         np = FindClientByWindow(windowStack[windowStackCurrent]);

         /* Skip this window if it no longer exists or is currently in
          * a state that doesn't allow focus.
          */
         if(np == NULL || !ShouldFocus(np, 1)) {
            continue;
         }

         /* Show the window.
          * Only when the walk completes do we update the stacking order. */
         RestackClients();
         if(np->state.status & STAT_MINIMIZED) {
            RestoreClient(np, 1);
            wasMinimized = 1;
         } else {
            wasMinimized = 0;
         }
         JXRaiseWindow(display, np->parent ? np->parent : np->window);
         FocusClient(np);
         break;

      }

   }

}
Exemple #4
0
/** Determine if there is anything to show for the specified entry. */
char ShouldShowEntry(const TaskEntry *tp)
{
   const ClientEntry *cp;
   for(cp = tp->clients; cp; cp = cp->next) {
      if(ShouldFocus(cp->client, 0)) {
         return 1;
      }
   }
   return 0;
}
Exemple #5
0
/** Determine if we should attempt to focus an entry. */
char ShouldFocusEntry(const TaskEntry *tp)
{
   const ClientEntry *cp;
   for(cp = tp->clients; cp; cp = cp->next) {
      if(cp->client->state.status & (STAT_CANFOCUS | STAT_TAKEFOCUS)) {
         if(ShouldFocus(cp->client, 1)) {
            return 1;
         }
      }
   }
   return 0;
}
Exemple #6
0
/** 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);
   }
}
Exemple #7
0
/** Focus the previous client in the task bar. */
void FocusPrevious(void)
{
   TaskEntry *tp;

   /* Find the current entry. */
   for(tp = taskEntries; tp; tp = tp->next) {
      ClientEntry *cp;
      for(cp = tp->clients; cp; cp = cp->next) {
         if(cp->client->state.status & (STAT_CANFOCUS | STAT_TAKEFOCUS)) {
            if(ShouldFocus(cp->client, 1)) {
               if(cp->client->state.status & STAT_ACTIVE) {
                  cp = cp->next;
                  goto ClientFound;
               }
            }
         }
      }
   }
ClientFound:

   /* Move to the previous group. */
   if(tp) {
      do {
         tp = tp->prev;
      } while(tp && !ShouldFocusEntry(tp));
   }
   if(!tp) {
      /* Wrap around; start at the end. */
      for(tp = taskEntriesTail; tp; tp = tp->prev) {
         if(ShouldFocusEntry(tp)) {
            break;
         }
      }
   }

   /* Focus the group if one exists. */
   if(tp) {
      FocusGroup(tp);
   }
}
Exemple #8
0
/** Move to the next window in the window stack. */
void WalkWindowStack(int forward) {

    ClientNode *np;
    int x;

    if(windowStack != NULL) {

        /* Loop until we either raise a window or go through them all. */
        for(x = 0; x < windowStackSize; x++) {

            /* Move to the next/previous window (wrap if needed). */
            if(forward) {
                windowStackCurrent = (windowStackCurrent + 1) % windowStackSize;
            } else {
                if(windowStackCurrent == 0) {
                    windowStackCurrent = windowStackSize;
                }
                --windowStackCurrent;
            }

            /* Look up the window. */
            np = FindClientByWindow(windowStack[windowStackCurrent]);

            /* Skip this window if it no longer exists or is currently in
             * a state that doesn't allow focus.
             */
            if(np == NULL || !ShouldFocus(np)) {
                continue;
            }

            /* Focus the window. We only raise the client when the
             * stack walk completes. */
            FocusClient(np);
            break;

        }

    }

}
Exemple #9
0
/** Draw a specific task bar. */
void Render(const TaskBarType *bp)
{
   TaskEntry *tp;
   char *displayName;
   ButtonNode button;
   int x, y;

   if(JUNLIKELY(shouldExit)) {
      return;
   }

   ClearTrayDrawable(bp->cp);
   if(!taskEntries) {
      UpdateSpecificTray(bp->cp->tray, bp->cp);
      return;
   }

   ResetButton(&button, bp->cp->pixmap);
   button.border = settings.trayDecorations == DECO_MOTIF;
   button.font = FONT_TASKLIST;
   button.height = bp->itemHeight;
   button.width = bp->itemWidth;
   button.text = NULL;

   x = 0;
   y = 0;
   for(tp = taskEntries; tp; tp = tp->next) {

      if(!ShouldShowEntry(tp)) {
         continue;
      }

      /* Check for an active or urgent window and count clients. */
      ClientEntry *cp;
      unsigned clientCount = 0;
      button.type = BUTTON_TASK;
      for(cp = tp->clients; cp; cp = cp->next) {
         if(ShouldFocus(cp->client, 0)) {
            const char flash = (cp->client->state.status & STAT_FLASH) != 0;
            const char active = (cp->client->state.status & STAT_ACTIVE)
               && IsClientOnCurrentDesktop(cp->client);
            if(flash || active) {
               if(button.type == BUTTON_TASK) {
                  button.type = BUTTON_TASK_ACTIVE;
               } else {
                  button.type = BUTTON_TASK;
               }
            }
            clientCount += 1;
         }
      }
      button.x = x;
      button.y = y;
      if(!tp->clients->client->icon) {
         button.icon = GetDefaultIcon();
      } else {
         button.icon = tp->clients->client->icon;
      }
      displayName = NULL;
      if(tp->clients->client->className && settings.groupTasks) {
         if(clientCount != 1) {
            const size_t len = strlen(tp->clients->client->className) + 16;
            displayName = Allocate(len);
            snprintf(displayName, len, "%s (%u)",
                     tp->clients->client->className, clientCount);
            button.text = displayName;
         } else {
            button.text = tp->clients->client->className;
         }
      } else {
         button.text = tp->clients->client->name;
      }
      DrawButton(&button);
      if(displayName) {
         Release(displayName);
      }

      if(bp->layout == LAYOUT_HORIZONTAL) {
         x += bp->itemWidth;
      } else {
         y += bp->itemHeight;
      }
   }

   UpdateSpecificTray(bp->cp->tray, bp->cp);

}
Exemple #10
0
/** Show the menu associated with a task list item. */
void ShowClientList(TaskBarType *bar, TaskEntry *tp)
{
   Menu *menu;
   MenuItem *item;
   ClientEntry *cp;

   const ScreenType *sp;
   int x, y;
   Window w;

   if(settings.groupTasks) {

      menu = Allocate(sizeof(Menu));
      menu->itemHeight = 0;
      menu->items = NULL;
      menu->label = NULL;

      item = CreateMenuItem(MENU_ITEM_NORMAL);
      item->name = CopyString(_("Close"));
      item->action.type = MA_CLOSE | MA_GROUP_MASK;
      item->action.context = tp;
      item->next = menu->items;
      menu->items = item;

      item = CreateMenuItem(MENU_ITEM_NORMAL);
      item->name = CopyString(_("Minimize"));
      item->action.type = MA_MINIMIZE | MA_GROUP_MASK;
      item->action.context = tp;
      item->next = menu->items;
      menu->items = item;

      item = CreateMenuItem(MENU_ITEM_NORMAL);
      item->name = CopyString(_("Restore"));
      item->action.type = MA_RESTORE | MA_GROUP_MASK;
      item->action.context = tp;
      item->next = menu->items;
      menu->items = item;

      item = CreateMenuItem(MENU_ITEM_SUBMENU);
      item->name = CopyString(_("Send To"));
      item->action.type = MA_SENDTO_MENU | MA_GROUP_MASK;
      item->action.context = tp;
      item->next = menu->items;
      menu->items = item;

      /* Load the separator and group actions. */
      item = CreateMenuItem(MENU_ITEM_SEPARATOR);
      item->next = menu->items;
      menu->items = item;

      /* Load the clients into the menu. */
      for(cp = tp->clients; cp; cp = cp->next) {
         if(!ShouldFocus(cp->client, 0)) {
            continue;
         }
         item = CreateMenuItem(MENU_ITEM_NORMAL);
         if(cp->client->state.status & STAT_MINIMIZED) {
            size_t len = 0;
            if(cp->client->name) {
               len = strlen(cp->client->name);
            }
            item->name = Allocate(len + 3);
            item->name[0] = '[';
            memcpy(&item->name[1], cp->client->name, len);
            item->name[len + 1] = ']';
            item->name[len + 2] = 0;
         } else {
            item->name = CopyString(cp->client->name);
         }
         item->icon = cp->client->icon ? cp->client->icon : GetDefaultIcon();
         item->action.type = MA_EXECUTE;
         item->action.context = cp->client;
         item->next = menu->items;
         menu->items = item;
      }
   } else {
      /* Not grouping clients. */
      menu = CreateWindowMenu(tp->clients->client);
   }

   /* Initialize and position the menu. */
   InitializeMenu(menu);
   sp = GetCurrentScreen(bar->cp->screenx, bar->cp->screeny);
   GetMousePosition(&x, &y, &w);
   if(bar->layout == LAYOUT_HORIZONTAL) {
      if(bar->cp->screeny + bar->cp->height / 2 < sp->y + sp->height / 2) {
         /* Bottom of the screen: menus go up. */
         y = bar->cp->screeny + bar->cp->height;
      } else {
         /* Top of the screen: menus go down. */
         y = bar->cp->screeny - menu->height;
      }
      x -= menu->width / 2;
      x = Max(x, sp->x);
   } else {
      if(bar->cp->screenx + bar->cp->width / 2 < sp->x + sp->width / 2) {
         /* Left side: menus go right. */
         x = bar->cp->screenx + bar->cp->width;
      } else {
         /* Right side: menus go left. */
         x = bar->cp->screenx - menu->width;
      }
      y -= menu->height / 2;
      y = Max(y, sp->y);
   }

   ShowMenu(menu, RunTaskBarCommand, x, y, 0);

   DestroyMenu(menu);

}
Exemple #11
0
/** 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);
}
Exemple #12
0
/** 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;
      }
   }

}