Exemple #1
0
/** Toggle the "show desktop" state. */
void ShowDesktop() {

   ClientNode *np;
   int layer;

   for(layer = 0; layer < LAYER_COUNT; layer++) {
      for(np = nodes[layer]; np; np = np->next) {

         /* Skip "nolist" items. */
         if(np->state.status & STAT_NOLIST) {
            continue;
         }

         if(showingDesktop) {
            if(np->state.status & STAT_SDESKTOP) {
               RestoreClient(np, 0);
            }
         } else if(np->state.desktop == currentDesktop
             || (np->state.status & STAT_STICKY)) {
            if(np->state.status & (STAT_MAPPED | STAT_SHADED)) {
               MinimizeClient(np);
               np->state.status |= STAT_SDESKTOP;
            }
         }
      }
   }

   showingDesktop = !showingDesktop;

   RestackClients();

}
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
/** 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 #5
0
/** 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;
   }

}
Exemple #6
0
/** 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;
   }

}
Exemple #7
0
/** 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
   }

}
Exemple #8
0
/** 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();
}
Exemple #9
0
/** Take the appropriate action for a click on a client border. */
void DispatchBorderButtonEvent(const XButtonEvent *event,
                               ClientNode *np)
{

   static Time lastClickTime = 0;
   static int lastX = 0, lastY = 0;
   static char doubleClickActive = 0;
   BorderActionType action;
   int bsize;

   /* Middle click starts a move unless it's over the maximize button. */
   action = GetBorderActionType(np, event->x, event->y);
   if(event->button == Button2 && action != BA_MAXIMIZE) {
      MoveClient(np, event->x, event->y);
      return;
   }

   /* Determine the size of the border. */
   if(np->state.border & BORDER_OUTLINE) {
      bsize = settings.borderWidth;
   } else {
      bsize = 0;
   }

   /* Other buttons are context sensitive. */
   switch(action & 0x0F) {
   case BA_RESIZE:   /* Border */
      if(event->type == ButtonPress) {
         if(event->button == Button1) {
            ResizeClient(np, action, event->x, event->y);
         } else if(event->button == Button3) {
            const int x = np->x + event->x - bsize;
            const int y = np->y + event->y - settings.titleHeight - bsize;
            ShowWindowMenu(np, x, y, 0);
         }
      }
      break;
   case BA_MOVE:     /* Title bar */
      if(event->button == Button1) {
         if(event->type == ButtonPress) {
            if(doubleClickActive
               && event->time != lastClickTime
               && event->time - lastClickTime <= settings.doubleClickSpeed
               && abs(event->x - lastX) <= settings.doubleClickDelta
               && abs(event->y - lastY) <= settings.doubleClickDelta) {
               MaximizeClientDefault(np);
               doubleClickActive = 0;
            } else {
               if(MoveClient(np, event->x, event->y)) {
                  doubleClickActive = 0;
               } else {
                  doubleClickActive = 1;
                  lastClickTime = event->time;
                  lastX = event->x;
                  lastY = event->y;
               }
            }
         }
      } else if(event->button == Button3) {
         const int x = np->x + event->x - bsize;
         const int y = np->y + event->y - settings.titleHeight - bsize;
         ShowWindowMenu(np, x, y, 0);
      } else if(event->button == Button4) {
         ShadeClient(np);
      } else if(event->button == Button5) {
         UnshadeClient(np);
      }
      break;
   case BA_MENU:  /* Menu button */
      if(event->button == Button4) {
         ShadeClient(np);
      } else if(event->button == Button5) {
         UnshadeClient(np);
      } else if(event->type == ButtonPress) {
         const int x = np->x + event->x - bsize;
         const int y = np->y + event->y - settings.titleHeight - bsize;
         ShowWindowMenu(np, x, y, 0);
      }
      break;
   case BA_CLOSE: /* Close button */
      if(event->type == ButtonRelease
         && (event->button == Button1 || event->button == Button3)) {
         DeleteClient(np);
      }
      break;
   case BA_MAXIMIZE: /* Maximize button */
      if(event->type == ButtonRelease) {
         switch(event->button) {
         case Button1:
            MaximizeClientDefault(np);
            break;
         case Button2:
            MaximizeClient(np, np->state.maxFlags ^ MAX_VERT);
            break;
         case Button3:
            MaximizeClient(np, np->state.maxFlags ^ MAX_HORIZ);
            break;
         default:
            break;
         }
      }
      break;
   case BA_MINIMIZE: /* Minimize button */
      if(event->type == ButtonRelease) {
         if(event->button == Button3) {
            if(np->state.status & STAT_SHADED) {
               UnshadeClient(np);
            } else {
               ShadeClient(np);
            }
         } else if(event->button == Button1) {
            MinimizeClient(np, 1);
         }
      }
      break;
   default:
      break;
   }
   DiscardEnterEvents();
}
Exemple #10
0
/** Handle a _NET_WM_STATE request. */
void HandleNetWMState(const XClientMessageEvent *event, ClientNode *np)
{

   unsigned int x;
   MaxFlags maxFlags;
   char actionStick;
   char actionShade;
   char actionFullScreen;
   char actionMinimize;
   char actionNolist;
   char actionNopager;
   char actionBelow;
   char actionAbove;

   /* Up to two actions to be applied together. */
   maxFlags = MAX_NONE;
   actionStick = 0;
   actionShade = 0;
   actionFullScreen = 0;
   actionMinimize = 0;
   actionNolist = 0;
   actionNopager = 0;
   actionBelow = 0;
   actionAbove = 0;

   for(x = 1; x <= 2; x++) {
      if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_STICKY]) {
         actionStick = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT]) {
         maxFlags |= MAX_VERT;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) {
         maxFlags |= MAX_HORIZ;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_SHADED]) {
         actionShade = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_FULLSCREEN]) {
         actionFullScreen = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_HIDDEN]) {
         actionMinimize = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR]) {
         actionNolist = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_SKIP_PAGER]) {
         actionNopager = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_BELOW]) {
         actionBelow = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_ABOVE]) {
         actionAbove = 1;
      }
   }

   switch(event->data.l[0]) {
   case 0: /* Remove */
      if(actionStick) {
         SetClientSticky(np, 0);
      }
      if(maxFlags != MAX_NONE && np->state.maxFlags) {
         MaximizeClient(np, np->state.maxFlags & ~maxFlags);
      }
      if(actionShade) {
         UnshadeClient(np);
      }
      if(actionFullScreen) {
         SetClientFullScreen(np, 0);
      }
      if(actionMinimize) {
         RestoreClient(np, 0);
      }
      if(actionNolist) {
         np->state.status &= ~STAT_NOLIST;
         RequireTaskUpdate();
      }
      if(actionNopager) {
         np->state.status &= ~STAT_NOPAGER;
         RequirePagerUpdate();
      }
      if(actionBelow && np->state.layer == LAYER_BELOW) {
         SetClientLayer(np, np->state.defaultLayer);
      }
      if(actionAbove && np->state.layer == LAYER_ABOVE) {
         SetClientLayer(np, np->state.defaultLayer);
      }
      break;
   case 1: /* Add */
      if(actionStick) {
         SetClientSticky(np, 1);
      }
      if(maxFlags != MAX_NONE) {
         MaximizeClient(np, np->state.maxFlags | maxFlags);
      }
      if(actionShade) {
         ShadeClient(np);
      }
      if(actionFullScreen) {
         SetClientFullScreen(np, 1);
      }
      if(actionMinimize) {
         MinimizeClient(np, 1);
      }
      if(actionNolist) {
         np->state.status |= STAT_NOLIST;
         RequireTaskUpdate();
      }
      if(actionNopager) {
         np->state.status |= STAT_NOPAGER;
         RequirePagerUpdate();
      }
      if(actionBelow) {
         SetClientLayer(np, LAYER_BELOW);
      }
      if(actionAbove) {
         SetClientLayer(np, LAYER_ABOVE);
      }
      break;
   case 2: /* Toggle */
      if(actionStick) {
         if(np->state.status & STAT_STICKY) {
            SetClientSticky(np, 0);
         } else {
            SetClientSticky(np, 1);
         }
      }
      if(maxFlags) {
         MaximizeClient(np, np->state.maxFlags ^ maxFlags);
      }
      if(actionShade) {
         if(np->state.status & STAT_SHADED) {
            UnshadeClient(np);
         } else {
            ShadeClient(np);
         }
      }
      if(actionFullScreen) {
         if(np->state.status & STAT_FULLSCREEN) {
            SetClientFullScreen(np, 0);
         } else {
            SetClientFullScreen(np, 1);
         }
      }
      if(actionBelow) {
         if(np->state.layer == LAYER_BELOW) {
            SetClientLayer(np, np->state.defaultLayer);
         } else {
            SetClientLayer(np, LAYER_BELOW);
         }
      }
      if(actionAbove) {
         if(np->state.layer == LAYER_ABOVE) {
            SetClientLayer(np, np->state.defaultLayer);
         } else {
            SetClientLayer(np, LAYER_ABOVE);
         }
      }
      /* Note that we don't handle toggling of hidden per EWMH
       * recommendations. */
      if(actionNolist) {
         np->state.status ^= STAT_NOLIST;
         RequireTaskUpdate();
      }
      if(actionNopager) {
         np->state.status ^= STAT_NOPAGER;
         RequirePagerUpdate();
      }
      break;
   default:
      Debug("bad _NET_WM_STATE action: %ld", event->data.l[0]);
      break;
   }

   /* Update _NET_WM_STATE if needed.
    * The state update is handled elsewhere for the other actions.
    */
   if(actionNolist | actionNopager | actionAbove | actionBelow) {
      WriteState(np);
   }

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

}
Exemple #12
0
/** 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;
   }
}
Exemple #13
0
/** Handle a _NET_WM_STATE request. */
void HandleNetWMState(const XClientMessageEvent *event, ClientNode *np) {

   int actionMaxH;
   int actionMaxV;
   int actionStick;
   int actionShade;
   int actionFullScreen;
   int actionMinimize;
   int actionNolist;
   int x;

   /* Up to two actions to be applied together, figure it out. */
   actionMaxH = 0;
   actionMaxV = 0;
   actionStick = 0;
   actionShade = 0;
   actionFullScreen = 0;
   actionMinimize = 0;
   actionNolist = 0;

   for(x = 1; x <= 2; x++) {
      if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_STICKY]) {
         actionStick = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT]) {
         actionMaxV = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) {
         actionMaxH = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_SHADED]) {
         actionShade = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_FULLSCREEN]) {
         actionFullScreen = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_HIDDEN]) {
         actionMinimize = 1;
      } else if(event->data.l[x]
         == (long)atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR]) {
         actionNolist = 1;
      }
   }

   switch(event->data.l[0]) {
   case 0: /* Remove */
      if(actionStick) {
         SetClientSticky(np, 0);
      }
      if(actionMaxH || actionMaxV) {
         if(np->state.status & (STAT_HMAX | STAT_VMAX)) {
            MaximizeClient(np, 0, 0);
         }
      }
      if(actionShade) {
         UnshadeClient(np);
      }
      if(actionFullScreen) {
         SetClientFullScreen(np, 0);
      }
      if(actionMinimize) {
         RestoreClient(np, 0);
      }
      if(actionNolist) {
         np->state.status &= ~STAT_NOLIST;
         UpdateTaskBar();
      }
      break;
   case 1: /* Add */
      if(actionStick) {
         SetClientSticky(np, 1);
      }
      if(!(np->state.status & (STAT_HMAX | STAT_VMAX))) {
         MaximizeClient(np, actionMaxH, actionMaxV);
      }
      if(actionShade) {
         ShadeClient(np);
      }
      if(actionFullScreen) {
         SetClientFullScreen(np, 1);
      }
      if(actionMinimize) {
         MinimizeClient(np);
      }
      if(actionNolist) {
         np->state.status |= STAT_NOLIST;
         UpdateTaskBar();
      }
      break;
   case 2: /* Toggle */
      if(actionStick) {
         if(np->state.status & STAT_STICKY) {
            SetClientSticky(np, 0);
         } else {
            SetClientSticky(np, 1);
         }
      }
      if(actionMaxH || actionMaxV) {
         MaximizeClient(np, actionMaxH, actionMaxV);
      }
      if(actionShade) {
         if(np->state.status & STAT_SHADED) {
            UnshadeClient(np);
         } else {
            ShadeClient(np);
         }
      }
      if(actionFullScreen) {
         if(np->state.status & STAT_FULLSCREEN) {
            SetClientFullScreen(np, 0);
         } else {
            SetClientFullScreen(np, 1);
         }
      }
      /* Note that we don't handle toggling of hidden per EWMH
       * recommendations. */
      if(actionNolist) {
         np->state.status ^= STAT_NOLIST;
         UpdateTaskBar();
      }
      break;
   default:
      Debug("bad _NET_WM_STATE action: %ld", event->data.l[0]);
      break;
   }
}
Exemple #14
0
/** 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);

   }

}
Exemple #15
0
/** Take the appropriate action for a click on a client border. */
void DispatchBorderButtonEvent(const XButtonEvent *event, ClientNode *np) {

   static Time lastClickTime = 0;
   static int lastX = 0, lastY = 0;
   static int doubleClickActive = 0;
   BorderActionType action;
   int bsize;

   action = GetBorderActionType(np, event->x, event->y);

   switch(action & 0x0F) {
   case BA_RESIZE:
      if(event->type == ButtonPress) {
         ResizeClient(np, action, event->x, event->y);
      }
      break;
   case BA_MOVE:
      if(event->type == ButtonPress) {
         if(doubleClickActive
            && abs(event->time - lastClickTime) > 0
            && abs(event->time - lastClickTime) <= doubleClickSpeed
            && abs(event->x - lastX) <= doubleClickDelta
            && abs(event->y - lastY) <= doubleClickDelta) {
            MaximizeClientDefault(np);
            doubleClickActive = 0;
         } else {
            if(MoveClient(np, event->x, event->y)) {
               doubleClickActive = 0;
            } else {
               doubleClickActive = 1;
               lastClickTime = event->time;
               lastX = event->x;
               lastY = event->y;
            }
         }
      }
      break;
   case BA_MENU:
      if(event->type == ButtonPress) {
         if(np->state.border & BORDER_OUTLINE) {
            bsize = borderWidth;
         } else {
            bsize = 0;
         }
         ShowWindowMenu(np, np->x + event->x - bsize,
            np->y + event->y - titleHeight - bsize);
      }
      break;
   case BA_CLOSE:
      if(event->type == ButtonRelease) {
         DeleteClient(np);
      }
      break;
   case BA_MAXIMIZE:
      if(event->type == ButtonRelease) {
         MaximizeClientDefault(np);
      }
      break;
   case BA_MINIMIZE:
      if(event->type == ButtonRelease) {
         MinimizeClient(np);
      }
      break;
   default:
      break;
   }

}