functions_warp.c revision 0bbfda8a
1/*
2 * Functions related to the warp ring
3 *
4 * There are functions that are _named_ like warp-ring funcs, but aren't
5 * really, and so aren't here.  Some examples are f.warphere which is
6 * workspaces-related, and f.warptoscreen which is screen-related.
7 *
8 * There are also funcs that aren't really ring related, but I've put
9 * here because they're still warping to window related, like f.warpto /
10 * f.warptoiconmgr.
11 */
12
13#include "ctwm.h"
14
15#include <string.h>
16
17#include "functions_internal.h"
18#include "iconmgr.h"
19#include "list.h"
20#include "otp.h"
21#include "screen.h"
22#include "win_iconify.h"
23#include "win_utils.h"
24
25
26static void WarpAlongRing(XButtonEvent *ev, bool forward);
27
28
29DFHANDLER(warpto)
30{
31	TwmWindow *tw;
32	int len;
33
34	len = strlen(action);
35
36#ifdef WARPTO_FROM_ICONMGR
37	/* XXX should be iconmgrp? */
38	if(len == 0 && tmp_win && tmp_win->iconmgr) {
39		printf("curren iconmgr entry: %s", tmp_win->iconmgr->Current);
40	}
41#endif /* #ifdef WARPTO_FROM_ICONMGR */
42	for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
43		if(!strncmp(action, tw->name, len)) {
44			break;
45		}
46		if(match(action, tw->name)) {
47			break;
48		}
49	}
50	if(!tw) {
51		for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
52			if(!strncmp(action, tw->class.res_name, len)) {
53				break;
54			}
55			if(match(action, tw->class.res_name)) {
56				break;
57			}
58		}
59		if(!tw) {
60			for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
61				if(!strncmp(action, tw->class.res_class, len)) {
62					break;
63				}
64				if(match(action, tw->class.res_class)) {
65					break;
66				}
67			}
68		}
69	}
70
71	if(tw) {
72		if(Scr->WarpUnmapped || tw->mapped) {
73			if(!tw->mapped) {
74				DeIconify(tw);
75			}
76			WarpToWindow(tw, Scr->RaiseOnWarp);
77		}
78	}
79	else {
80		XBell(dpy, 0);
81	}
82}
83
84
85DFHANDLER(warptoiconmgr)
86{
87	TwmWindow *tw, *raisewin = NULL;
88	int len;
89	Window iconwin = None;
90
91	len = strlen(action);
92	if(len == 0) {
93		if(tmp_win && tmp_win->iconmanagerlist) {
94			raisewin = tmp_win->iconmanagerlist->iconmgr->twm_win;
95			iconwin = tmp_win->iconmanagerlist->icon;
96		}
97		else if(Scr->iconmgr->active) {
98			raisewin = Scr->iconmgr->twm_win;
99			iconwin = Scr->iconmgr->active->w;
100		}
101	}
102	else {
103		for(tw = Scr->FirstWindow; tw != NULL; tw = tw->next) {
104			if(strncmp(action, tw->icon_name, len) == 0) {
105				if(tw->iconmanagerlist &&
106				                tw->iconmanagerlist->iconmgr->twm_win->mapped) {
107					raisewin = tw->iconmanagerlist->iconmgr->twm_win;
108					break;
109				}
110			}
111		}
112	}
113
114	if(raisewin) {
115		OtpRaise(raisewin, WinWin);
116		XWarpPointer(dpy, None, iconwin, 0, 0, 0, 0, 5, 5);
117	}
118	else {
119		XBell(dpy, 0);
120	}
121}
122
123
124/* Taken from vtwm version 5.3 */
125DFHANDLER(ring)
126{
127	if(tmp_win->ring.next || tmp_win->ring.prev) {
128		/* It's in the ring, let's take it out. */
129		TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next;
130
131		/*
132		* 1. Unlink window
133		* 2. If window was only thing in ring, null out ring
134		* 3. If window was ring leader, set to next (or null)
135		*/
136		if(prev) {
137			prev->ring.next = next;
138		}
139		if(next) {
140			next->ring.prev = prev;
141		}
142		if(Scr->Ring == tmp_win) {
143			Scr->Ring = (next != tmp_win ? next : NULL);
144		}
145
146		if(!Scr->Ring || Scr->RingLeader == tmp_win) {
147			Scr->RingLeader = Scr->Ring;
148		}
149		tmp_win->ring.next = tmp_win->ring.prev = NULL;
150	}
151	else {
152		/* Not in the ring, so put it in. */
153		if(Scr->Ring) {
154			tmp_win->ring.next = Scr->Ring->ring.next;
155			if(Scr->Ring->ring.next->ring.prev) {
156				Scr->Ring->ring.next->ring.prev = tmp_win;
157			}
158			Scr->Ring->ring.next = tmp_win;
159			tmp_win->ring.prev = Scr->Ring;
160		}
161		else {
162			tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win;
163		}
164	}
165	/*tmp_win->ring.cursor_valid = false;*/
166}
167
168
169DFHANDLER(warpring)
170{
171	switch(((char *)action)[0]) {
172		case 'n':
173			WarpAlongRing(&eventp->xbutton, true);
174			break;
175		case 'p':
176			WarpAlongRing(&eventp->xbutton, false);
177			break;
178		default:
179			XBell(dpy, 0);
180			break;
181	}
182}
183
184
185/*
186 * Synthetic function: this is used internally as the action in some
187 * magic menus like the TwmWindows et al.
188 */
189DFHANDLER(winwarp)
190{
191	tmp_win = (TwmWindow *)action;
192
193	if(! tmp_win) {
194		return;
195	}
196	if(Scr->WarpUnmapped || tmp_win->mapped) {
197		if(!tmp_win->mapped) {
198			DeIconify(tmp_win);
199		}
200		WarpToWindow(tmp_win, Scr->RaiseOnWarp);
201	}
202}
203
204
205/*
206 * Backend util for f.warpring
207 */
208static void
209WarpAlongRing(XButtonEvent *ev, bool forward)
210{
211	TwmWindow *r, *head;
212
213	if(Scr->RingLeader) {
214		head = Scr->RingLeader;
215	}
216	else if(!(head = Scr->Ring)) {
217		return;
218	}
219
220	if(forward) {
221		for(r = head->ring.next; r != head; r = r->ring.next) {
222			if(!r) {
223				break;
224			}
225			if(r->mapped && (Scr->WarpRingAnyWhere || visible(r))) {
226				break;
227			}
228		}
229	}
230	else {
231		for(r = head->ring.prev; r != head; r = r->ring.prev) {
232			if(!r) {
233				break;
234			}
235			if(r->mapped && (Scr->WarpRingAnyWhere || visible(r))) {
236				break;
237			}
238		}
239	}
240
241	/* Note: (Scr->Focus != r) is necessary when we move to a workspace that
242	   has a single window and we want warping to warp to it. */
243	if(r && (r != head || Scr->Focus != r)) {
244		TwmWindow *p = Scr->RingLeader, *t;
245
246		Scr->RingLeader = r;
247		WarpToWindow(r, true);
248
249		if(p && p->mapped &&
250		                (t = GetTwmWindow(ev->window)) &&
251		                p == t) {
252			p->ring.cursor_valid = true;
253			p->ring.curs_x = ev->x_root - t->frame_x;
254			p->ring.curs_y = ev->y_root - t->frame_y;
255#ifdef DEBUG
256			/* XXX This is the Tmp_win [now] internal to the event code? */
257			fprintf(stderr,
258			        "WarpAlongRing: cursor_valid := true; x := %d (%d-%d), y := %d (%d-%d)\n",
259			        Tmp_win->ring.curs_x, ev->x_root, t->frame_x, Tmp_win->ring.curs_y, ev->y_root,
260			        t->frame_y);
261#endif
262			/*
263			 * The check if the cursor position is inside the window is now
264			 * done in WarpToWindow().
265			 */
266		}
267	}
268}
269