alttab.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. int alttabn; /* move that many clients forward */
  2. int ntabs; /* number of active clients in tag */
  3. int isalt;
  4. Client **altsnext; /* array of all clients in the tag */
  5. Window alttabwin;
  6. void
  7. alttab()
  8. {
  9. Monitor *m = selmon;
  10. /* move to next window */
  11. if (m->sel && m->sel->snext) {
  12. alttabn++;
  13. if (alttabn >= ntabs)
  14. alttabn = 0; /* reset alttabn */
  15. focus(altsnext[alttabn]);
  16. restack(m);
  17. }
  18. /* redraw tab */
  19. XRaiseWindow(dpy, alttabwin);
  20. drawalttab(ntabs, 0, m);
  21. }
  22. void
  23. alttabend()
  24. {
  25. Monitor *m = selmon;
  26. Client *buff;
  27. int i;
  28. if (!isalt)
  29. return;
  30. /* Move all clients between first and choosen position,
  31. * one down in stack and put choosen client to the first position
  32. * so they remain in right order for the next time that alt-tab is used
  33. */
  34. if (ntabs > 1) {
  35. if (alttabn != 0) { /* if user picked original client do nothing */
  36. buff = altsnext[alttabn];
  37. if (alttabn > 1)
  38. for (i = alttabn; i > 0; i--)
  39. altsnext[i] = altsnext[i - 1];
  40. else /* swap them if there are just 2 clients */
  41. altsnext[alttabn] = altsnext[0];
  42. altsnext[0] = buff;
  43. }
  44. /* restack clients */
  45. for (i = ntabs - 1; i >= 0; i--) {
  46. focus(altsnext[i]);
  47. restack(m);
  48. }
  49. free(altsnext); /* free list of clients */
  50. }
  51. /* destroy the window */
  52. isalt = 0;
  53. ntabs = 0;
  54. XUnmapWindow(dpy, alttabwin);
  55. XDestroyWindow(dpy, alttabwin);
  56. }
  57. void
  58. drawalttab(int nwins, int first, Monitor *m)
  59. {
  60. Client *c;
  61. int i, h;
  62. int y = 0;
  63. int px = m->mx;
  64. int py = m->my;
  65. if (first) {
  66. XSetWindowAttributes wa = {
  67. .override_redirect = True,
  68. .background_pixel = 0,
  69. .border_pixel = 0,
  70. .colormap = cmap,
  71. .event_mask = ButtonPressMask|ExposureMask
  72. };
  73. /* decide position of tabwin */
  74. if (tabposx == 1)
  75. px = m->mx + (m->mw / 2) - (maxwtab / 2);
  76. else if (tabposx == 2)
  77. px = m->mx + m->mw - maxwtab;
  78. if (tabposy == 1)
  79. py = m->my + (m->mh / 2) - (maxhtab / 2);
  80. else if (tabposy == 2)
  81. py = m->my + m->mh - maxhtab;
  82. h = maxhtab;
  83. alttabwin = XCreateWindow(dpy, root, px, py, maxwtab, maxhtab, 2, depth,
  84. InputOutput, visual,
  85. CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
  86. XDefineCursor(dpy, alttabwin, cursor[CurNormal]->cursor);
  87. XMapRaised(dpy, alttabwin);
  88. }
  89. h = maxhtab / ntabs;
  90. for (i = 0; i < ntabs; i++) { /* draw all clients into tabwin */
  91. c = altsnext[i];
  92. if (!ISVISIBLE(c))
  93. continue;
  94. if (HIDDEN(c))
  95. continue;
  96. drw_setscheme(drw, scheme[c == m->sel ? SchemeSel : SchemeNorm]);
  97. drw_text(drw, 0, y, maxwtab, h, 0, c->name, 0, 0);
  98. y += h;
  99. }
  100. drw_setscheme(drw, scheme[SchemeNorm]);
  101. drw_map(drw, alttabwin, 0, 0, maxwtab, maxhtab);
  102. }
  103. void
  104. alttabstart(const Arg *arg)
  105. {
  106. Client *c;
  107. Monitor *m = selmon;
  108. int grabbed;
  109. int i;
  110. altsnext = NULL;
  111. if (alttabwin)
  112. alttabend();
  113. if (isalt == 1) {
  114. alttabend();
  115. return;
  116. }
  117. isalt = 1;
  118. alttabn = 0;
  119. ntabs = 0;
  120. for (c = m->clients; c; c = c->next) {
  121. if (!ISVISIBLE(c))
  122. continue;
  123. if (HIDDEN(c))
  124. continue;
  125. ++ntabs;
  126. }
  127. if (!ntabs) {
  128. alttabend();
  129. return;
  130. }
  131. altsnext = (Client **) malloc(ntabs * sizeof(Client *));
  132. for (i = 0, c = m->stack; c; c = c->snext) {
  133. if (!ISVISIBLE(c))
  134. continue;
  135. if (HIDDEN(c))
  136. continue;
  137. altsnext[i] = c;
  138. i++;
  139. }
  140. drawalttab(ntabs, 1, m);
  141. struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
  142. /* grab keyboard (take all input from keyboard) */
  143. grabbed = 1;
  144. for (i = 0; i < 1000; i++) {
  145. if (XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess)
  146. break;
  147. nanosleep(&ts, NULL);
  148. if (i == 1000 - 1)
  149. grabbed = 0;
  150. }
  151. XEvent event;
  152. alttab();
  153. if (grabbed == 0) {
  154. alttabend();
  155. return;
  156. }
  157. while (grabbed) {
  158. XNextEvent(dpy, &event);
  159. if (event.type == KeyPress || event.type == KeyRelease) {
  160. if (event.type == KeyRelease && event.xkey.keycode == tabmodkey) /* if mod key is released break cycle */
  161. break;
  162. if (event.type == KeyPress) {
  163. if (event.xkey.keycode == tabcyclekey) { /* if tab is pressed move to the next window */
  164. alttab();
  165. }
  166. }
  167. }
  168. }
  169. c = m->sel;
  170. alttabend();
  171. XUngrabKeyboard(dpy, CurrentTime);
  172. focus(c);
  173. restack(m);
  174. }