functions_win.c revision 0bbfda8a
10bbfda8aSnia/*
20bbfda8aSnia * Functions related to manipulating windows.
30bbfda8aSnia *
40bbfda8aSnia * This doesn't include stuff related to changing their occupation (in
50bbfda8aSnia * functions_workspaces.c), or moving/resizing (in
60bbfda8aSnia * functions_win_moveresize.c), or a few other cases of things
70bbfda8aSnia * peripherally involving windows.
80bbfda8aSnia */
90bbfda8aSnia
100bbfda8aSnia#include "ctwm.h"
110bbfda8aSnia
120bbfda8aSnia#include <stdlib.h>
130bbfda8aSnia
140bbfda8aSnia#include "colormaps.h"
150bbfda8aSnia#include "ctwm_atoms.h"
160bbfda8aSnia#include "events.h"
170bbfda8aSnia#include "event_handlers.h"
180bbfda8aSnia#include "functions.h"
190bbfda8aSnia#include "functions_defs.h"
200bbfda8aSnia#include "functions_internal.h"
210bbfda8aSnia#include "icons.h"
220bbfda8aSnia#include "occupation.h"
230bbfda8aSnia#include "otp.h"
240bbfda8aSnia#include "parse.h"
250bbfda8aSnia#include "screen.h"
260bbfda8aSnia#include "win_decorations.h"
270bbfda8aSnia#include "win_iconify.h"
280bbfda8aSnia#include "win_ops.h"
290bbfda8aSnia#include "win_utils.h"
300bbfda8aSnia#include "workspace_manager.h"
310bbfda8aSnia
320bbfda8aSnia
330bbfda8aSnia
340bbfda8aSnia/*
350bbfda8aSnia *************************************************************
360bbfda8aSnia *
370bbfda8aSnia * Moving windows on/off the AutoRaise/AutoLower lists
380bbfda8aSnia *
390bbfda8aSnia *************************************************************
400bbfda8aSnia */
410bbfda8aSniaDFHANDLER(autoraise)
420bbfda8aSnia{
430bbfda8aSnia	tmp_win->auto_raise = !tmp_win->auto_raise;
440bbfda8aSnia	if(tmp_win->auto_raise) {
450bbfda8aSnia		++(Scr->NumAutoRaises);
460bbfda8aSnia	}
470bbfda8aSnia	else {
480bbfda8aSnia		--(Scr->NumAutoRaises);
490bbfda8aSnia	}
500bbfda8aSnia}
510bbfda8aSnia
520bbfda8aSniaDFHANDLER(autolower)
530bbfda8aSnia{
540bbfda8aSnia	tmp_win->auto_lower = !tmp_win->auto_lower;
550bbfda8aSnia	if(tmp_win->auto_lower) {
560bbfda8aSnia		++(Scr->NumAutoLowers);
570bbfda8aSnia	}
580bbfda8aSnia	else {
590bbfda8aSnia		--(Scr->NumAutoLowers);
600bbfda8aSnia	}
610bbfda8aSnia}
620bbfda8aSnia
630bbfda8aSnia
640bbfda8aSnia
650bbfda8aSnia
660bbfda8aSnia/*
670bbfda8aSnia *************************************************************
680bbfda8aSnia *
690bbfda8aSnia * Raising and lowering
700bbfda8aSnia *
710bbfda8aSnia *************************************************************
720bbfda8aSnia */
730bbfda8aSnia
740bbfda8aSnia/* Separate function because raise and raiseorsqueeze can both need it */
750bbfda8aSniastatic void
760bbfda8aSniaraise_handler(EF_FULLPROTO)
770bbfda8aSnia{
780bbfda8aSnia	/* check to make sure raise is not from the WindowFunction */
790bbfda8aSnia	if(tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT)  {
800bbfda8aSnia		OtpRaise(tmp_win, IconWin);
810bbfda8aSnia	}
820bbfda8aSnia	else {
830bbfda8aSnia		OtpRaise(tmp_win, WinWin);
840bbfda8aSnia		WMapRaise(tmp_win);
850bbfda8aSnia	}
860bbfda8aSnia}
870bbfda8aSnia
880bbfda8aSniaDFHANDLER(raise)
890bbfda8aSnia{
900bbfda8aSnia	raise_handler(EF_ARGS);
910bbfda8aSnia}
920bbfda8aSnia
930bbfda8aSniaDFHANDLER(raiseorsqueeze)
940bbfda8aSnia{
950bbfda8aSnia	/* FIXME using the same double-click ConstrainedMoveTime here */
960bbfda8aSnia	if((eventp->xbutton.time - last_time) < ConstrainedMoveTime) {
970bbfda8aSnia		Squeeze(tmp_win);
980bbfda8aSnia		return;
990bbfda8aSnia	}
1000bbfda8aSnia	last_time = eventp->xbutton.time;
1010bbfda8aSnia
1020bbfda8aSnia	/* intentional fall-thru into F_RAISE */
1030bbfda8aSnia	raise_handler(EF_ARGS);
1040bbfda8aSnia}
1050bbfda8aSnia
1060bbfda8aSniaDFHANDLER(lower)
1070bbfda8aSnia{
1080bbfda8aSnia	if(tmp_win->icon && (w == tmp_win->icon->w)) {
1090bbfda8aSnia		OtpLower(tmp_win, IconWin);
1100bbfda8aSnia	}
1110bbfda8aSnia	else {
1120bbfda8aSnia		OtpLower(tmp_win, WinWin);
1130bbfda8aSnia		WMapLower(tmp_win);
1140bbfda8aSnia	}
1150bbfda8aSnia}
1160bbfda8aSnia
1170bbfda8aSniaDFHANDLER(raiselower)
1180bbfda8aSnia{
1190bbfda8aSnia	if(!WindowMoved) {
1200bbfda8aSnia		if(tmp_win->icon && w == tmp_win->icon->w) {
1210bbfda8aSnia			OtpRaiseLower(tmp_win, IconWin);
1220bbfda8aSnia		}
1230bbfda8aSnia		else {
1240bbfda8aSnia			OtpRaiseLower(tmp_win, WinWin);
1250bbfda8aSnia			WMapRaiseLower(tmp_win);
1260bbfda8aSnia		}
1270bbfda8aSnia	}
1280bbfda8aSnia}
1290bbfda8aSnia
1300bbfda8aSnia
1310bbfda8aSnia/*
1320bbfda8aSnia * Smaller raise/lower
1330bbfda8aSnia */
1340bbfda8aSniaDFHANDLER(tinyraise)
1350bbfda8aSnia{
1360bbfda8aSnia	/* check to make sure raise is not from the WindowFunction */
1370bbfda8aSnia	if(tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT) {
1380bbfda8aSnia		OtpTinyRaise(tmp_win, IconWin);
1390bbfda8aSnia	}
1400bbfda8aSnia	else {
1410bbfda8aSnia		OtpTinyRaise(tmp_win, WinWin);
1420bbfda8aSnia		WMapRaise(tmp_win);
1430bbfda8aSnia	}
1440bbfda8aSnia}
1450bbfda8aSnia
1460bbfda8aSniaDFHANDLER(tinylower)
1470bbfda8aSnia{
1480bbfda8aSnia	/* check to make sure raise is not from the WindowFunction */
1490bbfda8aSnia	if(tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT) {
1500bbfda8aSnia		OtpTinyLower(tmp_win, IconWin);
1510bbfda8aSnia	}
1520bbfda8aSnia	else {
1530bbfda8aSnia		OtpTinyLower(tmp_win, WinWin);
1540bbfda8aSnia		WMapLower(tmp_win);
1550bbfda8aSnia	}
1560bbfda8aSnia}
1570bbfda8aSnia
1580bbfda8aSnia
1590bbfda8aSnia/*
1600bbfda8aSnia * Raising/lowering a non-targetted window
1610bbfda8aSnia */
1620bbfda8aSniaDFHANDLER(circleup)
1630bbfda8aSnia{
1640bbfda8aSnia	OtpCirculateSubwindows(Scr->currentvs, RaiseLowest);
1650bbfda8aSnia}
1660bbfda8aSnia
1670bbfda8aSniaDFHANDLER(circledown)
1680bbfda8aSnia{
1690bbfda8aSnia	OtpCirculateSubwindows(Scr->currentvs, LowerHighest);
1700bbfda8aSnia}
1710bbfda8aSnia
1720bbfda8aSnia
1730bbfda8aSnia
1740bbfda8aSnia
1750bbfda8aSnia/*
1760bbfda8aSnia *************************************************************
1770bbfda8aSnia *
1780bbfda8aSnia * Iconification and its inverse.
1790bbfda8aSnia *
1800bbfda8aSnia *************************************************************
1810bbfda8aSnia */
1820bbfda8aSniastatic void
1830bbfda8aSniaiconify_handler(EF_FULLPROTO)
1840bbfda8aSnia{
1850bbfda8aSnia	if(tmp_win->isicon) {
1860bbfda8aSnia		DeIconify(tmp_win);
1870bbfda8aSnia	}
1880bbfda8aSnia	else if(func == F_ICONIFY) {
1890bbfda8aSnia		Iconify(tmp_win, eventp->xbutton.x_root - 5,
1900bbfda8aSnia		        eventp->xbutton.y_root - 5);
1910bbfda8aSnia	}
1920bbfda8aSnia}
1930bbfda8aSnia
1940bbfda8aSniaDFHANDLER(deiconify)
1950bbfda8aSnia{
1960bbfda8aSnia	iconify_handler(EF_ARGS);
1970bbfda8aSnia}
1980bbfda8aSniaDFHANDLER(iconify)
1990bbfda8aSnia{
2000bbfda8aSnia	iconify_handler(EF_ARGS);
2010bbfda8aSnia}
2020bbfda8aSnia
2030bbfda8aSnia
2040bbfda8aSnia/*
2050bbfda8aSnia * This is a synthetic function; it only exists as an action in some
2060bbfda8aSnia * magic menus like TwmWindows (x-ref f.winwarp as well).  It acts as a
2070bbfda8aSnia * sort of deiconify, so I've stuck it here.
2080bbfda8aSnia */
2090bbfda8aSniaDFHANDLER(popup)
2100bbfda8aSnia{
2110bbfda8aSnia	/*
2120bbfda8aSnia	 * This is a synthetic function; it exists only to be called
2130bbfda8aSnia	 * internally from the various magic menus like TwmWindows
2140bbfda8aSnia	 * etc.
2150bbfda8aSnia	 */
2160bbfda8aSnia	tmp_win = (TwmWindow *)action;
2170bbfda8aSnia	if(! tmp_win) {
2180bbfda8aSnia		return;
2190bbfda8aSnia	}
2200bbfda8aSnia	if(Scr->WindowFunction.func != 0) {
2210bbfda8aSnia		ExecuteFunction(Scr->WindowFunction.func,
2220bbfda8aSnia		                Scr->WindowFunction.item->action,
2230bbfda8aSnia		                w, tmp_win, eventp, C_FRAME, false);
2240bbfda8aSnia	}
2250bbfda8aSnia	else {
2260bbfda8aSnia		DeIconify(tmp_win);
2270bbfda8aSnia		OtpRaise(tmp_win, WinWin);
2280bbfda8aSnia	}
2290bbfda8aSnia}
2300bbfda8aSnia
2310bbfda8aSnia
2320bbfda8aSnia
2330bbfda8aSnia
2340bbfda8aSnia/*
2350bbfda8aSnia *************************************************************
2360bbfda8aSnia *
2370bbfda8aSnia * Focus locking
2380bbfda8aSnia *
2390bbfda8aSnia *************************************************************
2400bbfda8aSnia */
2410bbfda8aSniaDFHANDLER(focus)
2420bbfda8aSnia{
2430bbfda8aSnia	if(!tmp_win->isicon) {
2440bbfda8aSnia		if(!Scr->FocusRoot && Scr->Focus == tmp_win) {
2450bbfda8aSnia			FocusOnRoot();
2460bbfda8aSnia		}
2470bbfda8aSnia		else {
2480bbfda8aSnia			InstallWindowColormaps(0, tmp_win);
2490bbfda8aSnia			SetFocus(tmp_win, eventp->xbutton.time);
2500bbfda8aSnia			Scr->FocusRoot = false;
2510bbfda8aSnia		}
2520bbfda8aSnia	}
2530bbfda8aSnia}
2540bbfda8aSnia
2550bbfda8aSniaDFHANDLER(unfocus)
2560bbfda8aSnia{
2570bbfda8aSnia	FocusOnRoot();
2580bbfda8aSnia}
2590bbfda8aSnia
2600bbfda8aSnia
2610bbfda8aSnia
2620bbfda8aSnia
2630bbfda8aSnia/*
2640bbfda8aSnia *************************************************************
2650bbfda8aSnia *
2660bbfda8aSnia * Window destruction
2670bbfda8aSnia *
2680bbfda8aSnia *************************************************************
2690bbfda8aSnia */
2700bbfda8aSniastatic void
2710bbfda8aSniaSendDeleteWindowMessage(TwmWindow *tmp, Time timestamp)
2720bbfda8aSnia{
2730bbfda8aSnia	send_clientmessage(tmp->w, XA_WM_DELETE_WINDOW, timestamp);
2740bbfda8aSnia}
2750bbfda8aSnia
2760bbfda8aSniaDFHANDLER(delete)
2770bbfda8aSnia{
2780bbfda8aSnia	if(tmp_win->isiconmgr) {     /* don't send ourself a message */
2790bbfda8aSnia		HideIconManager();
2800bbfda8aSnia		return;
2810bbfda8aSnia	}
2820bbfda8aSnia	if(tmp_win->iswinbox || tmp_win->iswspmgr
2830bbfda8aSnia	                || (Scr->workSpaceMgr.occupyWindow
2840bbfda8aSnia	                    && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
2850bbfda8aSnia		XBell(dpy, 0);
2860bbfda8aSnia		return;
2870bbfda8aSnia	}
2880bbfda8aSnia	if(tmp_win->protocols & DoesWmDeleteWindow) {
2890bbfda8aSnia		SendDeleteWindowMessage(tmp_win, EventTime);
2900bbfda8aSnia		if(ButtonPressed != -1) {
2910bbfda8aSnia			XEvent kev;
2920bbfda8aSnia
2930bbfda8aSnia			XMaskEvent(dpy, ButtonReleaseMask, &kev);
2940bbfda8aSnia			if(kev.xbutton.window == tmp_win->w) {
2950bbfda8aSnia				kev.xbutton.window = Scr->Root;
2960bbfda8aSnia			}
2970bbfda8aSnia			XPutBackEvent(dpy, &kev);
2980bbfda8aSnia		}
2990bbfda8aSnia		return;
3000bbfda8aSnia	}
3010bbfda8aSnia	XBell(dpy, 0);
3020bbfda8aSnia}
3030bbfda8aSnia
3040bbfda8aSniaDFHANDLER(destroy)
3050bbfda8aSnia{
3060bbfda8aSnia	if(tmp_win->isiconmgr || tmp_win->iswinbox || tmp_win->iswspmgr
3070bbfda8aSnia	                || (Scr->workSpaceMgr.occupyWindow
3080bbfda8aSnia	                    && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
3090bbfda8aSnia		XBell(dpy, 0);
3100bbfda8aSnia		return;
3110bbfda8aSnia	}
3120bbfda8aSnia	XKillClient(dpy, tmp_win->w);
3130bbfda8aSnia	if(ButtonPressed != -1) {
3140bbfda8aSnia		XEvent kev;
3150bbfda8aSnia
3160bbfda8aSnia		XMaskEvent(dpy, ButtonReleaseMask, &kev);
3170bbfda8aSnia		if(kev.xbutton.window == tmp_win->w) {
3180bbfda8aSnia			kev.xbutton.window = Scr->Root;
3190bbfda8aSnia		}
3200bbfda8aSnia		XPutBackEvent(dpy, &kev);
3210bbfda8aSnia	}
3220bbfda8aSnia}
3230bbfda8aSnia
3240bbfda8aSniaDFHANDLER(deleteordestroy)
3250bbfda8aSnia{
3260bbfda8aSnia	if(tmp_win->isiconmgr) {
3270bbfda8aSnia		HideIconManager();
3280bbfda8aSnia		return;
3290bbfda8aSnia	}
3300bbfda8aSnia	if(tmp_win->iswinbox || tmp_win->iswspmgr
3310bbfda8aSnia	                || (Scr->workSpaceMgr.occupyWindow
3320bbfda8aSnia	                    && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) {
3330bbfda8aSnia		XBell(dpy, 0);
3340bbfda8aSnia		return;
3350bbfda8aSnia	}
3360bbfda8aSnia	if(tmp_win->protocols & DoesWmDeleteWindow) {
3370bbfda8aSnia		SendDeleteWindowMessage(tmp_win, EventTime);
3380bbfda8aSnia	}
3390bbfda8aSnia	else {
3400bbfda8aSnia		XKillClient(dpy, tmp_win->w);
3410bbfda8aSnia	}
3420bbfda8aSnia	if(ButtonPressed != -1) {
3430bbfda8aSnia		XEvent kev;
3440bbfda8aSnia
3450bbfda8aSnia		XMaskEvent(dpy, ButtonReleaseMask, &kev);
3460bbfda8aSnia		if(kev.xbutton.window == tmp_win->w) {
3470bbfda8aSnia			kev.xbutton.window = Scr->Root;
3480bbfda8aSnia		}
3490bbfda8aSnia		XPutBackEvent(dpy, &kev);
3500bbfda8aSnia	}
3510bbfda8aSnia}
3520bbfda8aSnia
3530bbfda8aSnia
3540bbfda8aSnia
3550bbfda8aSnia
3560bbfda8aSnia/*
3570bbfda8aSnia *************************************************************
3580bbfda8aSnia *
3590bbfda8aSnia * Messing with OnTopPriority bits
3600bbfda8aSnia *
3610bbfda8aSnia *************************************************************
3620bbfda8aSnia */
3630bbfda8aSniastatic void
3640bbfda8aSniaotp_priority_handler(EF_FULLPROTO)
3650bbfda8aSnia{
3660bbfda8aSnia	WinType wintype;
3670bbfda8aSnia	int pri;
3680bbfda8aSnia	char *endp;
3690bbfda8aSnia
3700bbfda8aSnia	if(tmp_win->icon && w == tmp_win->icon->w) {
3710bbfda8aSnia		wintype = IconWin;
3720bbfda8aSnia	}
3730bbfda8aSnia	else {
3740bbfda8aSnia		wintype = WinWin;
3750bbfda8aSnia	}
3760bbfda8aSnia	switch(func) {
3770bbfda8aSnia		case F_PRIORITYSWITCHING:
3780bbfda8aSnia			OtpToggleSwitching(tmp_win, wintype);
3790bbfda8aSnia			break;
3800bbfda8aSnia		case F_SETPRIORITY:
3810bbfda8aSnia			pri = (int)strtol(action, &endp, 10);
3820bbfda8aSnia			OtpSetPriority(tmp_win, wintype, pri,
3830bbfda8aSnia			               (*endp == '<' || *endp == 'b') ? Below : Above);
3840bbfda8aSnia			break;
3850bbfda8aSnia		case F_CHANGEPRIORITY:
3860bbfda8aSnia			OtpChangePriority(tmp_win, wintype, atoi(action));
3870bbfda8aSnia			break;
3880bbfda8aSnia		case F_SWITCHPRIORITY:
3890bbfda8aSnia			OtpSwitchPriority(tmp_win, wintype);
3900bbfda8aSnia			break;
3910bbfda8aSnia	}
3920bbfda8aSnia
3930bbfda8aSnia	/*
3940bbfda8aSnia	 * Stash up our current flags if there aren't any set yet.  This is
3950bbfda8aSnia	 * necessary because otherwise the EWMH prop we [may] stash below
3960bbfda8aSnia	 * would be taken as gospel on restart, when it shouldn't be.
3970bbfda8aSnia	 */
3980bbfda8aSnia	OtpStashAflagsFirstTime(tmp_win);
3990bbfda8aSnia
4000bbfda8aSnia#ifdef EWMH
4010bbfda8aSnia	/*
4020bbfda8aSnia	 * We changed the priority somehow, so we may have changed where it
4030bbfda8aSnia	 * sits relative to the middle.  So trigger rechecking/setting of the
4040bbfda8aSnia	 * _STATE_{ABOVE,BELOW}.  (_ABOVE in changes arg covers both)
4050bbfda8aSnia	 */
4060bbfda8aSnia	EwmhSet_NET_WM_STATE(tmp_win, EWMH_STATE_ABOVE);
4070bbfda8aSnia#endif /* EWMH */
4080bbfda8aSnia}
4090bbfda8aSniaDFHANDLER(priorityswitching)
4100bbfda8aSnia{
4110bbfda8aSnia	otp_priority_handler(EF_ARGS);
4120bbfda8aSnia}
4130bbfda8aSniaDFHANDLER(switchpriority)
4140bbfda8aSnia{
4150bbfda8aSnia	otp_priority_handler(EF_ARGS);
4160bbfda8aSnia}
4170bbfda8aSniaDFHANDLER(setpriority)
4180bbfda8aSnia{
4190bbfda8aSnia	otp_priority_handler(EF_ARGS);
4200bbfda8aSnia}
4210bbfda8aSniaDFHANDLER(changepriority)
4220bbfda8aSnia{
4230bbfda8aSnia	otp_priority_handler(EF_ARGS);
4240bbfda8aSnia}
4250bbfda8aSnia
4260bbfda8aSnia
4270bbfda8aSnia
4280bbfda8aSnia
4290bbfda8aSnia/*
4300bbfda8aSnia *************************************************************
4310bbfda8aSnia *
4320bbfda8aSnia * Some misc utilities
4330bbfda8aSnia *
4340bbfda8aSnia *************************************************************
4350bbfda8aSnia */
4360bbfda8aSniaDFHANDLER(saveyourself)
4370bbfda8aSnia{
4380bbfda8aSnia	if(tmp_win->protocols & DoesWmSaveYourself) {
4390bbfda8aSnia		send_clientmessage(tmp_win->w, XA_WM_SAVE_YOURSELF, EventTime);
4400bbfda8aSnia	}
4410bbfda8aSnia	else {
4420bbfda8aSnia		XBell(dpy, 0);
4430bbfda8aSnia	}
4440bbfda8aSnia}
4450bbfda8aSnia
4460bbfda8aSniaDFHANDLER(colormap)
4470bbfda8aSnia{
4480bbfda8aSnia	/* XXX Window targetting; should this be on the Defer list? */
4490bbfda8aSnia	if(strcmp(action, COLORMAP_NEXT) == 0) {
4500bbfda8aSnia		BumpWindowColormap(tmp_win, 1);
4510bbfda8aSnia	}
4520bbfda8aSnia	else if(strcmp(action, COLORMAP_PREV) == 0) {
4530bbfda8aSnia		BumpWindowColormap(tmp_win, -1);
4540bbfda8aSnia	}
4550bbfda8aSnia	else {
4560bbfda8aSnia		BumpWindowColormap(tmp_win, 0);
4570bbfda8aSnia	}
4580bbfda8aSnia}
4590bbfda8aSnia
4600bbfda8aSniaDFHANDLER(refresh)
4610bbfda8aSnia{
4620bbfda8aSnia	XSetWindowAttributes attributes;
4630bbfda8aSnia	unsigned long valuemask;
4640bbfda8aSnia
4650bbfda8aSnia	valuemask = CWBackPixel;
4660bbfda8aSnia	attributes.background_pixel = Scr->Black;
4670bbfda8aSnia	w = XCreateWindow(dpy, Scr->Root, 0, 0,
4680bbfda8aSnia	                  Scr->rootw,
4690bbfda8aSnia	                  Scr->rooth,
4700bbfda8aSnia	                  0,
4710bbfda8aSnia	                  CopyFromParent, CopyFromParent,
4720bbfda8aSnia	                  CopyFromParent, valuemask,
4730bbfda8aSnia	                  &attributes);
4740bbfda8aSnia	XMapWindow(dpy, w);
4750bbfda8aSnia	XDestroyWindow(dpy, w);
4760bbfda8aSnia	XFlush(dpy);
4770bbfda8aSnia
4780bbfda8aSnia}
4790bbfda8aSnia
4800bbfda8aSniaDFHANDLER(winrefresh)
4810bbfda8aSnia{
4820bbfda8aSnia	if(context == C_ICON && tmp_win->icon && tmp_win->icon->w)
4830bbfda8aSnia		w = XCreateSimpleWindow(dpy, tmp_win->icon->w,
4840bbfda8aSnia		                        0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
4850bbfda8aSnia	else
4860bbfda8aSnia		w = XCreateSimpleWindow(dpy, tmp_win->frame,
4870bbfda8aSnia		                        0, 0, 9999, 9999, 0, Scr->Black, Scr->Black);
4880bbfda8aSnia
4890bbfda8aSnia	XMapWindow(dpy, w);
4900bbfda8aSnia	XDestroyWindow(dpy, w);
4910bbfda8aSnia	XFlush(dpy);
4920bbfda8aSnia}
4930bbfda8aSnia
4940bbfda8aSnia
4950bbfda8aSnia
4960bbfda8aSnia
4970bbfda8aSnia/*
4980bbfda8aSnia *************************************************************
4990bbfda8aSnia *
5000bbfda8aSnia * Window squeezing related bits
5010bbfda8aSnia *
5020bbfda8aSnia *************************************************************
5030bbfda8aSnia */
5040bbfda8aSniaDFHANDLER(squeeze)
5050bbfda8aSnia{
5060bbfda8aSnia	Squeeze(tmp_win);
5070bbfda8aSnia}
5080bbfda8aSnia
5090bbfda8aSniaDFHANDLER(unsqueeze)
5100bbfda8aSnia{
5110bbfda8aSnia	if(tmp_win->squeezed) {
5120bbfda8aSnia		Squeeze(tmp_win);
5130bbfda8aSnia	}
5140bbfda8aSnia}
5150bbfda8aSnia
5160bbfda8aSnia
5170bbfda8aSniaDFHANDLER(movetitlebar)
5180bbfda8aSnia{
5190bbfda8aSnia	Window grabwin;
5200bbfda8aSnia	Window rootw;
5210bbfda8aSnia	int deltax = 0, newx = 0;
5220bbfda8aSnia	int origX;
5230bbfda8aSnia	int origNum;
5240bbfda8aSnia	SqueezeInfo *si;
5250bbfda8aSnia
5260bbfda8aSnia	PopDownMenu();
5270bbfda8aSnia	if(tmp_win->squeezed ||
5280bbfda8aSnia	                !tmp_win->squeeze_info ||
5290bbfda8aSnia	                !tmp_win->title_w ||
5300bbfda8aSnia	                context == C_ICON) {
5310bbfda8aSnia		XBell(dpy, 0);
5320bbfda8aSnia		return;
5330bbfda8aSnia	}
5340bbfda8aSnia
5350bbfda8aSnia	/* If the SqueezeInfo isn't copied yet, do it now */
5360bbfda8aSnia	if(!tmp_win->squeeze_info_copied) {
5370bbfda8aSnia		SqueezeInfo *s = malloc(sizeof(SqueezeInfo));
5380bbfda8aSnia		if(!s) {
5390bbfda8aSnia			return;
5400bbfda8aSnia		}
5410bbfda8aSnia		*s = *tmp_win->squeeze_info;
5420bbfda8aSnia		tmp_win->squeeze_info = s;
5430bbfda8aSnia		tmp_win->squeeze_info_copied = true;
5440bbfda8aSnia	}
5450bbfda8aSnia	si = tmp_win->squeeze_info;
5460bbfda8aSnia
5470bbfda8aSnia	if(si->denom != 0) {
5480bbfda8aSnia		int target_denom = tmp_win->frame_width;
5490bbfda8aSnia		/*
5500bbfda8aSnia		 * If not pixel based, scale the denominator to equal the
5510bbfda8aSnia		 * window width, so the numerator equals pixels.
5520bbfda8aSnia		 * That way we can just modify it by pixel units, just
5530bbfda8aSnia		 * like the other case.
5540bbfda8aSnia		 */
5550bbfda8aSnia
5560bbfda8aSnia		if(si->denom != target_denom) {
5570bbfda8aSnia			float scale = (float)target_denom / si->denom;
5580bbfda8aSnia			si->num *= scale;
5590bbfda8aSnia			si->denom = target_denom; /* s->denom *= scale; */
5600bbfda8aSnia		}
5610bbfda8aSnia	}
5620bbfda8aSnia
5630bbfda8aSnia	/* now move the mouse */
5640bbfda8aSnia	if(tmp_win->winbox) {
5650bbfda8aSnia		XTranslateCoordinates(dpy, Scr->Root, tmp_win->winbox->window,
5660bbfda8aSnia		                      eventp->xbutton.x_root, eventp->xbutton.y_root,
5670bbfda8aSnia		                      &eventp->xbutton.x_root, &eventp->xbutton.y_root, &JunkChild);
5680bbfda8aSnia	}
5690bbfda8aSnia	/*
5700bbfda8aSnia	 * the event is always a button event, since key events
5710bbfda8aSnia	 * are "weeded out" - although incompletely only
5720bbfda8aSnia	 * F_MOVE and F_RESIZE - in HandleKeyPress().
5730bbfda8aSnia	 */
5740bbfda8aSnia
5750bbfda8aSnia	/*
5760bbfda8aSnia	 * XXX This var may be actually unnecessary; it's used only
5770bbfda8aSnia	 * once as an arg to a later X call, but during that time I
5780bbfda8aSnia	 * don't believe anything can mutate eventp or anything near
5790bbfda8aSnia	 * the root.  However, due to the union nature of XEvent,
5800bbfda8aSnia	 * it's hard to be sure without more investigation, so I
5810bbfda8aSnia	 * leave the intermediate var for now.
5820bbfda8aSnia	 *
5830bbfda8aSnia	 * Note that we're looking inside the XButtonEvent member
5840bbfda8aSnia	 * here, but other bits of this code later look at the
5850bbfda8aSnia	 * XMotionEvent piece.  This should be further investigated
5860bbfda8aSnia	 * and resolved; they can't both be right (though the
5870bbfda8aSnia	 * structure of the structs are such that almost all the
5880bbfda8aSnia	 * similar elements are in the same place, at least in
5890bbfda8aSnia	 * theory).
5900bbfda8aSnia	 */
5910bbfda8aSnia	rootw = eventp->xbutton.root;
5920bbfda8aSnia
5930bbfda8aSnia	EventHandler[EnterNotify] = HandleUnknown;
5940bbfda8aSnia	EventHandler[LeaveNotify] = HandleUnknown;
5950bbfda8aSnia
5960bbfda8aSnia	if(!Scr->NoGrabServer) {
5970bbfda8aSnia		XGrabServer(dpy);
5980bbfda8aSnia	}
5990bbfda8aSnia
6000bbfda8aSnia	grabwin = Scr->Root;
6010bbfda8aSnia	if(tmp_win->winbox) {
6020bbfda8aSnia		grabwin = tmp_win->winbox->window;
6030bbfda8aSnia	}
6040bbfda8aSnia	XGrabPointer(dpy, grabwin, True,
6050bbfda8aSnia	             ButtonPressMask | ButtonReleaseMask |
6060bbfda8aSnia	             ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */
6070bbfda8aSnia	             GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime);
6080bbfda8aSnia
6090bbfda8aSnia#if 0   /* what's this for ? */
6100bbfda8aSnia	if(! tmp_win->icon || w != tmp_win->icon->w) {
6110bbfda8aSnia		XTranslateCoordinates(dpy, w, tmp_win->frame,
6120bbfda8aSnia		                      eventp->xbutton.x,
6130bbfda8aSnia		                      eventp->xbutton.y,
6140bbfda8aSnia		                      &DragX, &DragY, &JunkChild);
6150bbfda8aSnia
6160bbfda8aSnia		w = tmp_win->frame;
6170bbfda8aSnia	}
6180bbfda8aSnia#endif
6190bbfda8aSnia
6200bbfda8aSnia	DragWindow = None;
6210bbfda8aSnia
6220bbfda8aSnia	XGetGeometry(dpy, tmp_win->title_w, &JunkRoot, &origDragX, &origDragY,
6230bbfda8aSnia	             &DragWidth, &DragHeight, &DragBW,
6240bbfda8aSnia	             &JunkDepth);
6250bbfda8aSnia
6260bbfda8aSnia	origX = eventp->xbutton.x_root;
6270bbfda8aSnia	origNum = si->num;
6280bbfda8aSnia
6290bbfda8aSnia	if(menuFromFrameOrWindowOrTitlebar) {
6300bbfda8aSnia		/* warp the pointer to the middle of the window */
6310bbfda8aSnia		XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
6320bbfda8aSnia		             origDragX + DragWidth / 2,
6330bbfda8aSnia		             origDragY + DragHeight / 2);
6340bbfda8aSnia		XFlush(dpy);
6350bbfda8aSnia	}
6360bbfda8aSnia
6370bbfda8aSnia	while(1) {
6380bbfda8aSnia		long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
6390bbfda8aSnia		                    ButtonPress : ButtonRelease;
6400bbfda8aSnia		long movementMask = menuFromFrameOrWindowOrTitlebar ?
6410bbfda8aSnia		                    PointerMotionMask : ButtonMotionMask;
6420bbfda8aSnia
6430bbfda8aSnia		/* block until there is an interesting event */
6440bbfda8aSnia		XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
6450bbfda8aSnia		           EnterWindowMask | LeaveWindowMask |
6460bbfda8aSnia		           ExposureMask | movementMask |
6470bbfda8aSnia		           VisibilityChangeMask, &Event);
6480bbfda8aSnia
6490bbfda8aSnia		/* throw away enter and leave events until release */
6500bbfda8aSnia		if(Event.xany.type == EnterNotify ||
6510bbfda8aSnia		                Event.xany.type == LeaveNotify) {
6520bbfda8aSnia			continue;
6530bbfda8aSnia		}
6540bbfda8aSnia
6550bbfda8aSnia		if(Event.type == MotionNotify) {
6560bbfda8aSnia			/* discard any extra motion events before a logical release */
6570bbfda8aSnia			while(XCheckMaskEvent(dpy,
6580bbfda8aSnia			                      movementMask | releaseEvent, &Event)) {
6590bbfda8aSnia				if(Event.type == releaseEvent) {
6600bbfda8aSnia					break;
6610bbfda8aSnia				}
6620bbfda8aSnia			}
6630bbfda8aSnia		}
6640bbfda8aSnia
6650bbfda8aSnia		if(!DispatchEvent2()) {
6660bbfda8aSnia			continue;
6670bbfda8aSnia		}
6680bbfda8aSnia
6690bbfda8aSnia		if(Event.type == releaseEvent) {
6700bbfda8aSnia			break;
6710bbfda8aSnia		}
6720bbfda8aSnia
6730bbfda8aSnia		/* something left to do only if the pointer moved */
6740bbfda8aSnia		if(Event.type != MotionNotify) {
6750bbfda8aSnia			continue;
6760bbfda8aSnia		}
6770bbfda8aSnia
6780bbfda8aSnia		/* get current pointer pos, useful when there is lag */
6790bbfda8aSnia		XQueryPointer(dpy, rootw, &eventp->xmotion.root, &JunkChild,
6800bbfda8aSnia		              &eventp->xmotion.x_root, &eventp->xmotion.y_root,
6810bbfda8aSnia		              &JunkX, &JunkY, &JunkMask);
6820bbfda8aSnia
6830bbfda8aSnia		FixRootEvent(eventp);
6840bbfda8aSnia		if(tmp_win->winbox) {
6850bbfda8aSnia			XTranslateCoordinates(dpy, Scr->Root, tmp_win->winbox->window,
6860bbfda8aSnia			                      eventp->xmotion.x_root, eventp->xmotion.y_root,
6870bbfda8aSnia			                      &eventp->xmotion.x_root, &eventp->xmotion.y_root, &JunkChild);
6880bbfda8aSnia		}
6890bbfda8aSnia
6900bbfda8aSnia		if(!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) {
6910bbfda8aSnia			OtpRaise(tmp_win, WinWin);
6920bbfda8aSnia		}
6930bbfda8aSnia
6940bbfda8aSnia		deltax = eventp->xmotion.x_root - origX;
6950bbfda8aSnia		newx = origNum + deltax;
6960bbfda8aSnia
6970bbfda8aSnia		/*
6980bbfda8aSnia		 * Clamp to left and right.
6990bbfda8aSnia		 * If we're in pixel size, keep within [ 0, frame_width >.
7000bbfda8aSnia		 * If we're proportional, don't cross the 0.
7010bbfda8aSnia		 * Also don't let the nominator get bigger than the denominator.
7020bbfda8aSnia		 * Keep within [ -denom, -1] or [ 0, denom >.
7030bbfda8aSnia		 */
7040bbfda8aSnia		{
7050bbfda8aSnia			int wtmp = tmp_win->frame_width; /* or si->denom; if it were != 0 */
7060bbfda8aSnia			if(origNum < 0) {
7070bbfda8aSnia				if(newx >= 0) {
7080bbfda8aSnia					newx = -1;
7090bbfda8aSnia				}
7100bbfda8aSnia				else if(newx < -wtmp) {
7110bbfda8aSnia					newx = -wtmp;
7120bbfda8aSnia				}
7130bbfda8aSnia			}
7140bbfda8aSnia			else if(origNum >= 0) {
7150bbfda8aSnia				if(newx < 0) {
7160bbfda8aSnia					newx = 0;
7170bbfda8aSnia				}
7180bbfda8aSnia				else if(newx >= wtmp) {
7190bbfda8aSnia					newx = wtmp - 1;
7200bbfda8aSnia				}
7210bbfda8aSnia			}
7220bbfda8aSnia		}
7230bbfda8aSnia
7240bbfda8aSnia		si->num = newx;
7250bbfda8aSnia		/* This, finally, actually moves the title bar */
7260bbfda8aSnia		/* XXX pressing a second button should cancel and undo this */
7270bbfda8aSnia		SetFrameShape(tmp_win);
7280bbfda8aSnia	}
7290bbfda8aSnia
7300bbfda8aSnia	/*
7310bbfda8aSnia	 * The ButtonRelease handler will have taken care of
7320bbfda8aSnia	 * ungrabbing our pointer.
7330bbfda8aSnia	 */
7340bbfda8aSnia	return;
7350bbfda8aSnia}
736