#include #include #include #include #include #include #include "fvwm.h" #include "menus.h" #include "misc.h" #include "parse.h" #include "screen.h" #include "module.h" /*************************************************************************** * * Check to see if the pointer is on the edge of the screen, and scroll/page * if needed ***************************************************************************/ void HandlePaging(int HorWarpSize, int VertWarpSize, int *xl, int *yt, int *delta_x, int *delta_y,Bool Grab) { int x,y,total; *delta_x = 0; *delta_y = 0; /* Windows obscured by the scroll region won't receive * EnterNotify events. Broadcast this event so * applications that care (FvwmTaskBar) can decide what to do. */ Broadcast(M_SCROLLREGION, 2, *xl, *yt, 0,0,0,0,0); if((Scr.ScrollResistance >= 10000)|| ((HorWarpSize ==0)&&(VertWarpSize==0))) return; /* need to move the viewport */ if(( Scr.VxMax == 0 || (*xl >= SCROLL_REGION && *xl < Scr.MyDisplayWidth - SCROLL_REGION)) && ( Scr.VyMax == 0 || (*yt >= SCROLL_REGION && *yt < Scr.MyDisplayHeight - SCROLL_REGION))) return; total = 0; while(total < Scr.ScrollResistance) { sleep_a_little(10000); total+=10; if(XCheckWindowEvent(dpy,Scr.PanFrameTop.win, LeaveWindowMask,&Event)) { StashEventTime(&Event); return; } if(XCheckWindowEvent(dpy,Scr.PanFrameBottom.win, LeaveWindowMask,&Event)) { StashEventTime(&Event); return; } if(XCheckWindowEvent(dpy,Scr.PanFrameLeft.win, LeaveWindowMask,&Event)) { StashEventTime(&Event); return; } if(XCheckWindowEvent(dpy,Scr.PanFrameRight.win, LeaveWindowMask,&Event)) { StashEventTime(&Event); return; } } XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &x, &y, &JunkX, &JunkY, &JunkMask); /* Turn off the rubberband if its on */ MoveOutline(Scr.Root,0,0,0,0); /* Move the viewport */ /* and/or move the cursor back to the approximate correct location */ /* that is, the same place on the virtual desktop that it */ /* started at */ if( x= Scr.MyDisplayWidth-SCROLL_REGION) *delta_x = HorWarpSize; else *delta_x = 0; if (Scr.VxMax == 0) *delta_x = 0; if( y= Scr.MyDisplayHeight-SCROLL_REGION) *delta_y = VertWarpSize; else *delta_y = 0; if (Scr.VyMax == 0) *delta_y = 0; /* Ouch! lots of bounds checking */ if(Scr.Vx + *delta_x < 0) { if (Scr.flags & EdgeWrapX) { *delta_x = Scr.VxMax; *xl = x + Scr.MyDisplayWidth; } } else if(Scr.Vx + *delta_x > Scr.VxMax) { if (Scr.flags & EdgeWrapX) { *delta_x = -Scr.VxMax; *xl = x - Scr.MyDisplayWidth; } } else *xl = x - *delta_x; if(Scr.Vy + *delta_y < 0) { if (Scr.flags & EdgeWrapY) { *delta_y = Scr.VyMax; *yt = y + Scr.MyDisplayHeight; } } else if(Scr.Vy + *delta_y > Scr.VyMax) { if (Scr.flags & EdgeWrapY) { *delta_y = -Scr.VyMax; *yt = y - Scr.MyDisplayHeight; } } else *yt = y - *delta_y; if(*xl <= SCROLL_REGION) *xl = SCROLL_REGION+1; if(*yt <= SCROLL_REGION) *yt = SCROLL_REGION+1; if(*xl >= Scr.MyDisplayWidth - SCROLL_REGION) *xl = Scr.MyDisplayWidth - SCROLL_REGION -1; if(*yt >= Scr.MyDisplayHeight - SCROLL_REGION) *yt = Scr.MyDisplayHeight - SCROLL_REGION -1; if((*delta_x != 0)||(*delta_y!=0)) { if(Grab) XGrabServer(dpy); XWarpPointer(dpy,None,Scr.Root,0,0,0,0,*xl,*yt); MoveViewport(Scr.Vx + *delta_x,Scr.Vy + *delta_y,False); XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, xl, yt, &JunkX, &JunkY, &JunkMask); if(Grab) XUngrabServer(dpy); } } /* the root window is surrounded by four window slices, which are InputOnly. * So you can see 'through' them, but they eat the input. An EnterEvent in * one of these windows causes a Paging. The windows have the according cursor * pointing in the pan direction or are hidden if there is no more panning * in that direction. This is mostly intended to get a panning even atop * of Motif applications, which does not work yet. It seems Motif windows * eat all mouse events. * * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94 */ /*************************************************************************** * checkPanFrames hides PanFrames if they are on the very border of the * VIRTUELL screen and EdgeWrap for that direction is off. * (A special cursor for the EdgeWrap border could be nice) HEDU ****************************************************************************/ void checkPanFrames(void) { int wrapX = (Scr.flags & EdgeWrapX); int wrapY = (Scr.flags & EdgeWrapY); if(!(Scr.flags & WindowsCaptured)) return; /* Remove Pan frames if paging by edge-scroll is permanently or * temporarily disabled */ if(Scr.EdgeScrollY == 0) { XUnmapWindow(dpy,Scr.PanFrameTop.win); Scr.PanFrameTop.isMapped=False; XUnmapWindow (dpy,Scr.PanFrameBottom.win); Scr.PanFrameBottom.isMapped=False; } if(Scr.EdgeScrollX == 0) { XUnmapWindow(dpy,Scr.PanFrameLeft.win); Scr.PanFrameLeft.isMapped=False; XUnmapWindow (dpy,Scr.PanFrameRight.win); Scr.PanFrameRight.isMapped=False; } if((Scr.EdgeScrollX == 0)&&(Scr.EdgeScrollY == 0)) return; /* LEFT, hide only if EdgeWrap is off */ if (Scr.Vx==0 && Scr.PanFrameLeft.isMapped && (!wrapX)) { XUnmapWindow(dpy,Scr.PanFrameLeft.win); Scr.PanFrameLeft.isMapped=False; } else if (Scr.Vx > 0 && Scr.PanFrameLeft.isMapped==False) { XMapRaised(dpy,Scr.PanFrameLeft.win); Scr.PanFrameLeft.isMapped=True; } /* RIGHT, hide only if EdgeWrap is off */ if (Scr.Vx == Scr.VxMax && Scr.PanFrameRight.isMapped && (!wrapX)) { XUnmapWindow (dpy,Scr.PanFrameRight.win); Scr.PanFrameRight.isMapped=False; } else if (Scr.Vx < Scr.VxMax && Scr.PanFrameRight.isMapped==False) { XMapRaised(dpy,Scr.PanFrameRight.win); Scr.PanFrameRight.isMapped=True; } /* TOP, hide only if EdgeWrap is off */ if (Scr.Vy==0 && Scr.PanFrameTop.isMapped && (!wrapY)) { XUnmapWindow(dpy,Scr.PanFrameTop.win); Scr.PanFrameTop.isMapped=False; } else if (Scr.Vy > 0 && Scr.PanFrameTop.isMapped==False) { XMapRaised(dpy,Scr.PanFrameTop.win); Scr.PanFrameTop.isMapped=True; } /* BOTTOM, hide only if EdgeWrap is off */ if (Scr.Vy == Scr.VyMax && Scr.PanFrameBottom.isMapped && (!wrapY)) { XUnmapWindow (dpy,Scr.PanFrameBottom.win); Scr.PanFrameBottom.isMapped=False; } else if (Scr.Vy < Scr.VyMax && Scr.PanFrameBottom.isMapped==False) { XMapRaised(dpy,Scr.PanFrameBottom.win); Scr.PanFrameBottom.isMapped=True; } } /**************************************************************************** * * Gotta make sure these things are on top of everything else, or they * don't work! * * For some reason, this seems to be unneeded. * ***************************************************************************/ void raisePanFrames(void) { if (Scr.PanFrameTop.isMapped) XRaiseWindow(dpy,Scr.PanFrameTop.win); if (Scr.PanFrameLeft.isMapped) XRaiseWindow(dpy,Scr.PanFrameLeft.win); if (Scr.PanFrameRight.isMapped) XRaiseWindow(dpy,Scr.PanFrameRight.win); if (Scr.PanFrameBottom.isMapped) XRaiseWindow(dpy,Scr.PanFrameBottom.win); } /**************************************************************************** * * Creates the windows for edge-scrolling * ****************************************************************************/ void initPanFrames() { XSetWindowAttributes attributes; /* attributes for create */ unsigned long valuemask; attributes.event_mask = EnterWindowMask | LeaveWindowMask | VisibilityChangeMask; valuemask = CWEventMask | CWCursor; attributes.cursor = Scr.FvwmCursors[LEFT]; Scr.PanFrameLeft.win = XCreateWindow (dpy, Scr.Root, 0, PAN_FRAME_THICKNESS, PAN_FRAME_THICKNESS, Scr.MyDisplayHeight-2*PAN_FRAME_THICKNESS, 0, /* no border */ CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); attributes.cursor = Scr.FvwmCursors[TOP]; Scr.PanFrameTop.win = XCreateWindow (dpy, Scr.Root, 0, 0, Scr.MyDisplayWidth, PAN_FRAME_THICKNESS, 0, /* no border */ CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); attributes.cursor = Scr.FvwmCursors[RIGHT]; Scr.PanFrameRight.win = XCreateWindow (dpy, Scr.Root, Scr.MyDisplayWidth-PAN_FRAME_THICKNESS, PAN_FRAME_THICKNESS, PAN_FRAME_THICKNESS, Scr.MyDisplayHeight-2*PAN_FRAME_THICKNESS, 0, /* no border */ CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); attributes.cursor = Scr.FvwmCursors[BOTTOM]; Scr.PanFrameBottom.win = XCreateWindow (dpy, Scr.Root, 0, Scr.MyDisplayHeight-PAN_FRAME_THICKNESS, Scr.MyDisplayWidth, PAN_FRAME_THICKNESS, 0, /* no border */ CopyFromParent, InputOnly, CopyFromParent, valuemask, &attributes); Scr.PanFrameLeft.isMapped = Scr.PanFrameTop.isMapped = Scr.PanFrameRight.isMapped = Scr.PanFrameBottom.isMapped = False; } /*************************************************************************** * * Moves the viewport within thwe virtual desktop * ***************************************************************************/ void MoveViewport(int newx, int newy, Bool grab) { FvwmWindow *t; int deltax,deltay; if(grab) XGrabServer(dpy); if(newx > Scr.VxMax) newx = Scr.VxMax; if(newy > Scr.VyMax) newy = Scr.VyMax; if(newx <0) newx = 0; if(newy <0) newy = 0; deltay = Scr.Vy - newy; deltax = Scr.Vx - newx; Scr.Vx = newx; Scr.Vy = newy; Broadcast(M_NEW_PAGE, 5, Scr.Vx, Scr.Vy, Scr.CurrentDesk, Scr.VxMax, Scr.VyMax, 0, 0); if((deltax!=0)||(deltay!=0)) { for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { /* If the window is iconified, and sticky Icons is set, * then the window should essentially be sticky */ if(!((t->flags & ICONIFIED)&&(t->flags & StickyIcon)) && (!(t->flags & STICKY))) { if(!(t->flags & StickyIcon)) { t->icon_x_loc += deltax; t->icon_xl_loc += deltax; t->icon_y_loc += deltay; if(t->icon_pixmap_w != None) XMoveWindow(dpy,t->icon_pixmap_w,t->icon_x_loc, t->icon_y_loc); if(t->icon_w != None) XMoveWindow(dpy,t->icon_w,t->icon_x_loc, t->icon_y_loc+t->icon_p_height); if(!(t->flags &ICON_UNMAPPED)) Broadcast(M_ICON_LOCATION,7,t->w,t->frame, (unsigned long)t, t->icon_x_loc,t->icon_y_loc, t->icon_w_width, t->icon_w_height+t->icon_p_height); } SetupFrame (t, t->frame_x+ deltax, t->frame_y + deltay, t->frame_width, t->frame_height,FALSE); } } for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { /* If its an icon, and its sticking, autoplace it so * that it doesn't wind up on top a a stationary * icon */ if(((t->flags & STICKY)||(t->flags & StickyIcon))&& (t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&& (!(t->flags & ICON_UNMAPPED))) AutoPlace(t); } } checkPanFrames(); /* do this with PanFrames too ??? HEDU */ while (XCheckTypedEvent(dpy, MotionNotify, &Event)) StashEventTime(&Event); if (grab) XUngrabServer(dpy); } /************************************************************************** * * Move to a new desktop * *************************************************************************/ void changeDesks_func(XEvent *eventp,Window w,FvwmWindow *tmp_win, unsigned long context,char *action, int *Module) { int n,val1, val1_unit, val2, val2_unit; n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit); changeDesks(val1,val2); } void changeDesks(int val1, int val2) { int oldDesk; FvwmWindow *FocusWin = 0, *t; static FvwmWindow *StickyWin = 0; oldDesk = Scr.CurrentDesk; if(val1 != 0) { Scr.CurrentDesk = Scr.CurrentDesk + val1; } else { Scr.CurrentDesk = val2; if(Scr.CurrentDesk == oldDesk) return; } Broadcast(M_NEW_DESK, 1, Scr.CurrentDesk, 0, 0, 0, 0, 0, 0); /* Scan the window list, mapping windows on the new Desk, * unmapping windows on the old Desk */ XGrabServer(dpy); for (t=Scr.FvwmRoot.next; t!=NULL; t=t->next) { /* Only change mapping for non-sticky windows */ if (!((t->flags & ICONIFIED) && (t->flags & StickyIcon)) && (!(t->flags & STICKY)) && (!(t->flags & ICON_UNMAPPED))) { if(t->Desk == oldDesk) { if (Scr.Focus == t) t->FocusDesk = oldDesk; else t->FocusDesk = -1; UnmapIt(t); } else if(t->Desk == Scr.CurrentDesk) { MapIt(t); if (t->FocusDesk == Scr.CurrentDesk) { FocusWin = t; } } } else { /* Window is sticky */ t->Desk = Scr.CurrentDesk; if (Scr.Focus == t) { t->FocusDesk =oldDesk; StickyWin = t; } } } XUngrabServer(dpy); for (t=Scr.FvwmRoot.next; t!=NULL; t=t->next) { /* If its an icon, and its sticking, autoplace it so * that it doesn't wind up on top a a stationary * icon */ if(((t->flags & STICKY)||(t->flags & StickyIcon))&& (t->flags & ICONIFIED)&&(!(t->flags & ICON_MOVED))&& (!(t->flags & ICON_UNMAPPED))) AutoPlace(t); } if ((FocusWin) && (FocusWin->flags & ClickToFocus)) #ifndef NO_REMEMBER_FOCUS SetFocus(FocusWin->w, FocusWin,1); /* OK, someone beat me up, but I don't like this. If you are a predominantly * focus-follows-mouse person, but put in one sticky click-to-focus window * (typically because you don't really want to give focus to this window), * then the following lines are screwed up. */ /* else if (StickyWin && (StickyWin->flags && STICKY)) SetFocus(StickyWin->w, StickyWin,1); */ else #endif SetFocus(Scr.NoFocusWin, NULL, 1); } /************************************************************************** * * Move to a new desktop * *************************************************************************/ void changeWindowsDesk(XEvent *eventp,Window w,FvwmWindow *t, unsigned long context,char *action, int *Module) { long val1; int val1_unit,n; if (DeferExecution(eventp, &w, &t, &context, SELECT, ButtonRelease)) return; if(t == NULL) return; n = GetOneArgument(action, &val1, &val1_unit); if(val1 == t->Desk) return; /* Scan the window list, mapping windows on the new Desk, * unmapping windows on the old Desk */ /* Only change mapping for non-sticky windows */ if(!((t->flags & ICONIFIED)&&(t->flags & StickyIcon)) && (!(t->flags & STICKY))&&(!(t->flags & ICON_UNMAPPED))) { if(t->Desk == Scr.CurrentDesk) { t->Desk = val1; UnmapIt(t); } else if(val1 == Scr.CurrentDesk) { t->Desk = val1; /* If its an icon, auto-place it */ if(t->flags & ICONIFIED) AutoPlace(t); MapIt(t); } else t->Desk = val1; } BroadcastConfig(M_CONFIGURE_WINDOW,t); } void scroll(XEvent *eventp,Window w,FvwmWindow *tmp_win,unsigned long context, char *action, int *Module) { int x,y; int val1, val2, val1_unit,val2_unit,n; n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit); if((val1 > -100000)&&(val1 < 100000)) x=Scr.Vx + val1*val1_unit/100; else x = Scr.Vx + (val1/1000)*val1_unit/100; if((val2 > -100000)&&(val2 < 100000)) y=Scr.Vy + val2*val2_unit/100; else y = Scr.Vy + (val2/1000)*val2_unit/100; if(((val1 <= -100000)||(val1 >= 100000))&&(x>Scr.VxMax)) { x = 0; y += Scr.MyDisplayHeight; if(y > Scr.VyMax) y=0; } if(((val1 <= -100000)||(val1 >= 100000))&&(x<0)) { x = Scr.VxMax; y -= Scr.MyDisplayHeight; if(y < 0) y=Scr.VyMax; } if(((val2 <= -100000)||(val2>= 100000))&&(y>Scr.VyMax)) { y = 0; x += Scr.MyDisplayWidth; if(x > Scr.VxMax) x=0; } if(((val2 <= -100000)||(val2>= 100000))&&(y<0)) { y = Scr.VyMax; x -= Scr.MyDisplayWidth; if(x < 0) x=Scr.VxMax; } MoveViewport(x,y,True); } void goto_page_func(XEvent *eventp,Window w,FvwmWindow *tmp_win, unsigned long context,char *action, int *Module) { int val1, val2, val1_unit,val2_unit,n,x,y; n = GetTwoArguments(action, &val1, &val2, &val1_unit, &val2_unit); if(n != 2) { fvwm_msg(ERR,"goto_page_func","GotoPage requires two arguments"); return; } if((val1_unit != Scr.MyDisplayWidth)|| (val2_unit != Scr.MyDisplayHeight)) { fvwm_msg(ERR,"goto_page_func","GotoPage arguments should be unitless"); } x=val1*Scr.MyDisplayWidth; y=val2*Scr.MyDisplayHeight; MoveViewport(x,y,True); }