1999-10-04 15:06:00 -07:00
|
|
|
/*
|
2004-01-19 14:30:35 -08:00
|
|
|
* Copyright (C) 2000-2004 Carsten Haitzler, Geoff Harrison and various contributors
|
2000-04-05 16:22:56 -07:00
|
|
|
*
|
1999-10-04 15:06:00 -07:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to
|
|
|
|
* deal in the Software without restriction, including without limitation the
|
|
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
* sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2000-04-05 16:22:56 -07:00
|
|
|
*
|
1999-10-04 15:06:00 -07:00
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies of the Software, its documentation and marketing & publicity
|
|
|
|
* materials, and acknowledgment shall be given in the documentation, materials
|
|
|
|
* and software packages that this Software was used.
|
2000-04-05 16:22:56 -07:00
|
|
|
*
|
1999-10-04 15:06:00 -07:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
1999-08-17 15:56:46 -07:00
|
|
|
/*
|
|
|
|
* Author: Merlin Hughes
|
|
|
|
* - merlin@merlin.org
|
|
|
|
*
|
|
|
|
* This code is free software.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* TODO: The Warp Focus Title Window could list all windows in the
|
|
|
|
* warp ring with pretty window icons, and display which one is
|
|
|
|
* currently selected instead of just the title of the currently
|
|
|
|
* selected one.
|
|
|
|
*/
|
|
|
|
#include "E.h"
|
2004-12-28 15:46:49 -08:00
|
|
|
#include <X11/keysym.h>
|
1999-08-17 15:56:46 -07:00
|
|
|
|
2004-04-18 12:26:32 -07:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
EWin *ewin;
|
|
|
|
Window win;
|
|
|
|
char *txt;
|
|
|
|
} WarplistItem;
|
|
|
|
|
2004-12-28 15:46:49 -08:00
|
|
|
static void WarpFocusHandleEvent(XEvent * ev, void *prm);
|
1999-08-17 15:56:46 -07:00
|
|
|
|
|
|
|
static int warpFocusIndex = 0;
|
|
|
|
static char warpFocusTitleShowing = 0;
|
|
|
|
static Window warpFocusTitleWindow = 0;
|
2004-03-18 16:27:16 -08:00
|
|
|
static unsigned int warpFocusKey = 0;
|
2004-04-18 12:26:32 -07:00
|
|
|
static int warplist_num = 0;
|
|
|
|
static WarplistItem *warplist;
|
1999-08-17 15:56:46 -07:00
|
|
|
|
2003-08-10 08:44:47 -07:00
|
|
|
static void
|
1999-08-17 15:56:46 -07:00
|
|
|
WarpFocusShowTitle(EWin * ewin)
|
|
|
|
{
|
|
|
|
TextClass *tc;
|
|
|
|
ImageClass *ic;
|
|
|
|
char pq;
|
|
|
|
int i, x, y, w, h, num, ww, hh;
|
|
|
|
static int mw, mh;
|
2004-04-18 12:26:32 -07:00
|
|
|
char s[1024];
|
1999-08-17 15:56:46 -07:00
|
|
|
|
2004-12-28 15:46:49 -08:00
|
|
|
tc = TextclassFind("WARPFOCUS", 0);
|
1999-08-17 15:56:46 -07:00
|
|
|
if (!tc)
|
2004-12-28 15:46:49 -08:00
|
|
|
tc = TextclassFind("COORDS", 1);
|
|
|
|
|
|
|
|
ic = ImageclassFind("WARPFOCUS", 0);
|
1999-08-17 15:56:46 -07:00
|
|
|
if (!ic)
|
2004-12-28 15:46:49 -08:00
|
|
|
ic = ImageclassFind("COORDS", 1);
|
|
|
|
|
1999-08-17 15:56:46 -07:00
|
|
|
if ((!ic) || (!tc))
|
|
|
|
return;
|
2003-08-10 08:44:47 -07:00
|
|
|
|
1999-08-17 15:56:46 -07:00
|
|
|
if (!warpFocusTitleWindow)
|
2004-12-28 15:46:49 -08:00
|
|
|
{
|
|
|
|
warpFocusTitleWindow = ECreateWindow(VRoot.win, 0, 0, 1, 1, 1);
|
|
|
|
EventCallbackRegister(warpFocusTitleWindow, 0, WarpFocusHandleEvent,
|
|
|
|
NULL);
|
|
|
|
}
|
1999-08-17 15:56:46 -07:00
|
|
|
|
2004-04-09 05:59:56 -07:00
|
|
|
pq = Mode.queue_up;
|
|
|
|
Mode.queue_up = 0;
|
1999-08-17 15:56:46 -07:00
|
|
|
XRaiseWindow(disp, warpFocusTitleWindow);
|
2003-08-10 08:44:47 -07:00
|
|
|
|
1999-08-17 15:56:46 -07:00
|
|
|
if (!warpFocusTitleShowing)
|
2000-07-26 11:00:47 -07:00
|
|
|
{
|
2003-05-22 12:15:03 -07:00
|
|
|
EWin **lst;
|
1999-08-17 15:56:46 -07:00
|
|
|
|
2003-05-22 12:15:03 -07:00
|
|
|
w = 0;
|
|
|
|
h = 0;
|
|
|
|
lst = (EWin **) ListItemType(&num, LIST_TYPE_WARP_RING);
|
|
|
|
if (lst)
|
|
|
|
{
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2004-04-18 12:26:32 -07:00
|
|
|
warplist_num++;
|
|
|
|
warplist = Erealloc(warplist,
|
|
|
|
warplist_num * sizeof(WarplistItem));
|
|
|
|
warplist[warplist_num - 1].win =
|
2003-05-22 12:15:03 -07:00
|
|
|
ECreateWindow(warpFocusTitleWindow, 0, 0, 1, 1, 0);
|
2004-04-18 12:26:32 -07:00
|
|
|
EMapWindow(disp, warplist[warplist_num - 1].win);
|
|
|
|
warplist[warplist_num - 1].ewin = lst[i];
|
|
|
|
Esnprintf(s, sizeof(s), (lst[i]->iconified) ? "[%s]" : "%s",
|
2005-01-09 14:36:01 -08:00
|
|
|
EwinGetName(lst[i]));
|
2004-04-18 12:26:32 -07:00
|
|
|
warplist[warplist_num - 1].txt = strdup(s);
|
|
|
|
TextSize(tc, 0, 0, 0, warplist[warplist_num - 1].txt, &ww,
|
|
|
|
&hh, 17);
|
2003-05-22 12:15:03 -07:00
|
|
|
if (ww > w)
|
|
|
|
w = ww;
|
|
|
|
if (hh > h)
|
|
|
|
h = hh;
|
|
|
|
}
|
|
|
|
Efree(lst);
|
|
|
|
}
|
|
|
|
w += (ic->padding.left + ic->padding.right);
|
|
|
|
h += (ic->padding.top + ic->padding.bottom);
|
2004-07-02 17:58:19 -07:00
|
|
|
GetPointerScreenAvailableArea(&x, &y, &ww, &hh);
|
2003-05-22 12:15:03 -07:00
|
|
|
x += (ww - w) / 2;
|
2004-04-18 12:26:32 -07:00
|
|
|
y += (hh - h * warplist_num) / 2;
|
2003-05-22 12:15:03 -07:00
|
|
|
mw = w;
|
|
|
|
mh = h;
|
|
|
|
EMoveResizeWindow(disp, warpFocusTitleWindow, x, y, w,
|
2004-04-18 12:26:32 -07:00
|
|
|
(h * warplist_num));
|
|
|
|
for (i = 0; i < warplist_num; i++)
|
2003-05-22 12:15:03 -07:00
|
|
|
{
|
2004-04-18 12:26:32 -07:00
|
|
|
EMoveResizeWindow(disp, warplist[i].win, 0, (h * i), mw, mh);
|
|
|
|
if (ewin == warplist[i].ewin)
|
2004-12-28 15:46:49 -08:00
|
|
|
ImageclassApply(ic, warplist[i].win, mw, mh, 0, 0,
|
|
|
|
STATE_CLICKED, 0, ST_WARPLIST);
|
2003-05-22 12:15:03 -07:00
|
|
|
else
|
2004-12-28 15:46:49 -08:00
|
|
|
ImageclassApply(ic, warplist[i].win, mw, mh, 0, 0, STATE_NORMAL,
|
|
|
|
0, ST_WARPLIST);
|
2003-05-22 12:15:03 -07:00
|
|
|
}
|
|
|
|
PropagateShapes(warpFocusTitleWindow);
|
|
|
|
EMapWindow(disp, warpFocusTitleWindow);
|
2003-08-10 08:44:47 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Grab the keyboard. The grab is automatically released when
|
|
|
|
* WarpFocusHideTitle unmaps warpFocusTitleWindow.
|
|
|
|
*/
|
|
|
|
XGrabKeyboard(disp, warpFocusTitleWindow, False, GrabModeAsync,
|
|
|
|
GrabModeAsync, CurrentTime);
|
2000-07-26 11:00:47 -07:00
|
|
|
}
|
2003-08-10 08:44:47 -07:00
|
|
|
|
2004-04-18 12:26:32 -07:00
|
|
|
for (i = 0; i < warplist_num; i++)
|
2000-07-26 11:00:47 -07:00
|
|
|
{
|
2004-04-18 12:26:32 -07:00
|
|
|
if (!FindItem((char *)warplist[i].ewin, 0, LIST_FINDBY_POINTER,
|
2004-04-01 14:41:22 -08:00
|
|
|
LIST_TYPE_EWIN))
|
2004-04-18 12:26:32 -07:00
|
|
|
warplist[i].ewin = NULL;
|
|
|
|
if (warplist[i].ewin)
|
2003-05-22 12:15:03 -07:00
|
|
|
{
|
2004-04-18 12:26:32 -07:00
|
|
|
int state;
|
|
|
|
|
|
|
|
state = (ewin == warplist[i].ewin) ? STATE_CLICKED : STATE_NORMAL;
|
2004-02-28 17:30:18 -08:00
|
|
|
|
2004-12-28 15:46:49 -08:00
|
|
|
ImageclassApply(ic, warplist[i].win, mw, mh, 0, 0, state, 0,
|
|
|
|
ST_WARPLIST);
|
|
|
|
TextclassApply(ic, warplist[i].win, mw, mh, 0, 0, state, 0, tc,
|
|
|
|
warplist[i].txt);
|
2003-05-22 12:15:03 -07:00
|
|
|
}
|
2000-07-26 11:00:47 -07:00
|
|
|
}
|
2003-08-10 08:44:47 -07:00
|
|
|
|
1999-08-17 15:56:46 -07:00
|
|
|
PropagateShapes(warpFocusTitleWindow);
|
2004-04-09 05:59:56 -07:00
|
|
|
Mode.queue_up = pq;
|
1999-08-17 15:56:46 -07:00
|
|
|
XFlush(disp);
|
|
|
|
warpFocusTitleShowing = 1;
|
|
|
|
}
|
|
|
|
|
2003-08-10 08:44:47 -07:00
|
|
|
static void
|
1999-08-17 15:56:46 -07:00
|
|
|
WarpFocusHideTitle(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (warpFocusTitleWindow)
|
2000-07-26 11:00:47 -07:00
|
|
|
{
|
2003-05-22 12:15:03 -07:00
|
|
|
EUnmapWindow(disp, warpFocusTitleWindow);
|
2004-04-18 12:26:32 -07:00
|
|
|
for (i = 0; i < warplist_num; i++)
|
|
|
|
{
|
|
|
|
EDestroyWindow(disp, warplist[i].win);
|
|
|
|
Efree(warplist[i].txt);
|
|
|
|
}
|
2000-07-26 11:00:47 -07:00
|
|
|
}
|
2003-08-10 08:44:47 -07:00
|
|
|
|
2004-04-18 12:26:32 -07:00
|
|
|
if (warplist)
|
|
|
|
Efree(warplist);
|
|
|
|
warplist = NULL;
|
|
|
|
warplist_num = 0;
|
1999-08-17 15:56:46 -07:00
|
|
|
warpFocusTitleShowing = 0;
|
|
|
|
}
|
2004-12-28 15:46:49 -08:00
|
|
|
|
|
|
|
void
|
|
|
|
WarpFocus(int delta)
|
|
|
|
{
|
|
|
|
EWin *const *lst0;
|
|
|
|
EWin **lst, *ewin;
|
|
|
|
int i, num0, num;
|
|
|
|
|
|
|
|
EDBUG(5, "WarpFocus");
|
|
|
|
|
|
|
|
/* Remember invoking keycode (ugly hack) */
|
|
|
|
if (!warpFocusTitleShowing)
|
|
|
|
warpFocusKey = Mode.last_keycode;
|
|
|
|
|
|
|
|
lst = (EWin **) ListItemType(&num, LIST_TYPE_WARP_RING);
|
|
|
|
if (!lst)
|
|
|
|
{
|
|
|
|
lst0 = EwinListFocusGet(&num0);
|
|
|
|
num = 0;
|
|
|
|
lst = NULL;
|
|
|
|
for (i = num0 - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
ewin = lst0[i];
|
|
|
|
if ( /* Either visible or iconified */
|
|
|
|
((EwinIsOnScreen(ewin)) || (ewin->iconified)) &&
|
|
|
|
/* Exclude windows that explicitely say so */
|
|
|
|
(!ewin->skipfocus) &&
|
|
|
|
/* Keep shaded windows if conf say so */
|
|
|
|
((!ewin->shaded) || (Conf.warplist.showshaded)) &&
|
|
|
|
/* Keep sticky windows if conf say so */
|
|
|
|
((!EoIsSticky(ewin)) || (Conf.warplist.showsticky)) &&
|
|
|
|
/* Keep iconified windows if conf say so */
|
|
|
|
((!ewin->iconified) || (Conf.warplist.showiconified)))
|
|
|
|
AddItem(ewin, "", 0, LIST_TYPE_WARP_RING);
|
|
|
|
}
|
|
|
|
MoveItemToListBottom(GetFocusEwin(), LIST_TYPE_WARP_RING);
|
|
|
|
lst = (EWin **) ListItemType(&num, LIST_TYPE_WARP_RING);
|
|
|
|
warpFocusIndex = num - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lst)
|
|
|
|
{
|
|
|
|
warpFocusIndex = (warpFocusIndex + num + delta) % num;
|
|
|
|
ewin = lst[warpFocusIndex];
|
|
|
|
if (!FindItem((char *)ewin, 0, LIST_FINDBY_POINTER, LIST_TYPE_EWIN))
|
|
|
|
ewin = NULL;
|
|
|
|
if (ewin)
|
|
|
|
{
|
|
|
|
if (Conf.focus.raise_on_next)
|
|
|
|
RaiseEwin(ewin);
|
|
|
|
if (Conf.focus.warp_on_next)
|
|
|
|
if (ewin != Mode.mouse_over_ewin && !ewin->iconified)
|
|
|
|
XWarpPointer(disp, None, EoGetWin(ewin), 0, 0, 0, 0,
|
|
|
|
EoGetW(ewin) / 2, EoGetH(ewin) / 2);
|
|
|
|
if (Conf.warplist.warpfocused)
|
|
|
|
FocusToEWin(ewin, FOCUS_SET);
|
|
|
|
WarpFocusShowTitle(ewin);
|
|
|
|
}
|
|
|
|
Efree(lst);
|
|
|
|
}
|
|
|
|
|
|
|
|
EDBUG_RETURN_;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
WarpFocusFinish(void)
|
|
|
|
{
|
|
|
|
EWin **lst, *ewin;
|
|
|
|
int num;
|
|
|
|
|
|
|
|
EDBUG(5, "WarpFocusFinish");
|
|
|
|
|
|
|
|
lst = (EWin **) ListItemType(&num, LIST_TYPE_WARP_RING);
|
|
|
|
if (!lst)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ewin = lst[warpFocusIndex];
|
|
|
|
|
|
|
|
WarpFocusHideTitle();
|
|
|
|
if (!FindItem((char *)ewin, 0, LIST_FINDBY_POINTER, LIST_TYPE_EWIN))
|
|
|
|
ewin = NULL;
|
|
|
|
if (ewin)
|
|
|
|
{
|
|
|
|
if (Conf.warplist.showiconified && ewin->iconified)
|
|
|
|
EwinDeIconify(ewin);
|
|
|
|
if (Conf.warplist.raise_on_select)
|
|
|
|
RaiseEwin(ewin);
|
|
|
|
if (Conf.warplist.warp_on_select)
|
|
|
|
if (ewin != Mode.mouse_over_ewin)
|
|
|
|
XWarpPointer(disp, None, EoGetWin(ewin), 0, 0, 0, 0,
|
|
|
|
EoGetW(ewin) / 2, EoGetH(ewin) / 2);
|
|
|
|
FocusToEWin(ewin, FOCUS_SET);
|
|
|
|
}
|
|
|
|
Efree(lst);
|
|
|
|
|
|
|
|
while (RemoveItem("", 0, LIST_FINDBY_NONE, LIST_TYPE_WARP_RING));
|
|
|
|
|
|
|
|
done:
|
|
|
|
EDBUG_RETURN_;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
WarpFocusHandleEvent(XEvent * ev, void *prm __UNUSED__)
|
|
|
|
{
|
|
|
|
EDBUG(5, "WarpFocusHandleEvent");
|
|
|
|
|
|
|
|
switch (ev->type)
|
|
|
|
{
|
|
|
|
#if 0 /* Not necessary when sampling keycode in events.c */
|
|
|
|
case KeyPress:
|
|
|
|
if (warpFocusTitleShowing && ev->xany.window == VRoot.win)
|
|
|
|
warpFocusKey = ev->xkey.keycode;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case KeyRelease:
|
|
|
|
if (warpFocusTitleShowing && ev->xkey.keycode != warpFocusKey)
|
|
|
|
WarpFocusFinish();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
WarplistInit(void)
|
|
|
|
{
|
|
|
|
#if 0 /* Not necessary when sampling keycode in events.c */
|
|
|
|
/* Ugly hack to get the invoking key press */
|
|
|
|
EventCallbackRegister(VRoot.win, 0, WarpFocusHandleEvent, NULL);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Warplist module
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
WarplistSighan(int sig, void *prm __UNUSED__)
|
|
|
|
{
|
|
|
|
switch (sig)
|
|
|
|
{
|
|
|
|
case ESIGNAL_INIT:
|
|
|
|
WarplistInit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const CfgItem WarplistCfgItems[] = {
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, enable, 1),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, showsticky, 1),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, showshaded, 1),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, showiconified, 0),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, warpfocused, 1),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, raise_on_select, 1),
|
|
|
|
CFG_ITEM_BOOL(Conf.warplist, warp_on_select, 0),
|
|
|
|
};
|
|
|
|
#define N_CFG_ITEMS (sizeof(WarplistCfgItems)/sizeof(CfgItem))
|
|
|
|
|
|
|
|
EModule ModWarplist = {
|
|
|
|
"warplist", "warp",
|
|
|
|
WarplistSighan,
|
|
|
|
{0, NULL},
|
|
|
|
{N_CFG_ITEMS, WarplistCfgItems}
|
|
|
|
};
|