/**************************************************************************** * This module is all new * by Rob Nation ****************************************************************************/ /*********************************************************************** * * fvwm pager handling code * ***********************************************************************/ #include "../configure.h" #include #include #include #include "fvwm.h" #include "menus.h" #include "misc.h" #include "parse.h" #include "screen.h" #include "module.h" extern XEvent Event; XGCValues Globalgcv; unsigned long Globalgcm; void DrawPartitionLines(void); FvwmWindow *FindCounterpart(Window target); Bool pagerOn = True; Bool EnablePagerRedraw = True; Bool DoHandlePageing = True; /**************************************************************************** * Cause the pager window to be re-drawn * * Trying to get clever - re-draw the pager by causing an expose event, * the really redraw only when an expose arrives. Advantage is that the * number of re-draws will be minimized ***************************************************************************/ void RedrawPager() { #ifndef NO_PAGER if((Scr.FvwmPager)&&(EnablePagerRedraw)) XClearArea(dpy,Scr.Pager_w, 0, 0, Scr.FvwmPager->frame_width, Scr.FvwmPager->frame_height,True); #endif } void ReallyRedrawPager() { #ifndef NO_PAGER FvwmWindow *t; Pixel TextColor,BackColor; if(!Scr.FvwmPager) return; flush_expose (Scr.Pager_w); flush_expose (Scr.CPagerWin); if(Scr.PagerFont.height > 0) { if(Scr.Hilite != NULL) { if(!(Scr.Hilite->flags & STICKY)&& (!(Scr.Hilite->flags&ICONIFIED)||(!(Scr.Hilite->flags & SUPPRESSICON)))&& (!(Scr.Hilite->flags&ICONIFIED)||(!(Scr.flags & StickyIcons)))&& (Scr.Hilite->icon_name != NULL)) { TextColor = Scr.HiColors.fore; BackColor = Scr.HiColors.back; NewFontAndColor(Scr.PagerFont.font->fid,TextColor,BackColor); flush_expose(Scr.Hilite->pager_view); XDrawImageString (dpy, Scr.Hilite->pager_view, Scr.FontGC, 2,Scr.PagerFont.y+2, Scr.Hilite->icon_name, strlen(Scr.Hilite->icon_name)); } } for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { if(t != Scr.Hilite) { if(!(t->flags & STICKY)&& (!(t->flags & ICONIFIED)||(!(t->flags & SUPPRESSICON)))&& (!(t->flags & ICONIFIED)||(!(Scr.flags & StickyIcons)))&& (t->icon_name != NULL)) { TextColor = t->TextPixel; BackColor = t->BackPixel; NewFontAndColor(Scr.PagerFont.font->fid,TextColor,BackColor); flush_expose(t->pager_view); XDrawImageString (dpy, t->pager_view, Scr.FontGC, 2,Scr.PagerFont.y+2, t->icon_name, strlen(t->icon_name)); } } } } DrawPartitionLines(); #endif } #ifndef NO_PAGER void DrawPartitionLines(void) { int y, y1, y2, x, x1, x2; int MaxW,MaxH,width,height; MaxW = Scr.VxMax + Scr.MyDisplayWidth; MaxH = Scr.VyMax + Scr.MyDisplayHeight; width = Scr.FvwmPager->frame_width - 2*Scr.FvwmPager->boundary_width; height = Scr.FvwmPager->frame_height - Scr.FvwmPager->title_height - 2*Scr.FvwmPager->boundary_width; x = Scr.MyDisplayWidth; y1 = 0; y2 = height; while(x < MaxW) { x1 = x*width/MaxW; XDrawLine(dpy,Scr.Pager_w,Scr.NormalGC,x1,y1,x1,y2); x += Scr.MyDisplayWidth; } y = Scr.MyDisplayHeight; x1 = 0; x2 = width; while(y < MaxH) { y1 = y*height/MaxH; XDrawLine(dpy,Scr.Pager_w,Scr.NormalGC,x1,y1,x2,y1); y += Scr.MyDisplayHeight; } } #endif void SwitchPages(Bool align, Bool ChangeFocus) { #ifndef NO_PAGER int x,y; unsigned int width,height; FvwmWindow *tmp_win; Window dumwin; if(!Scr.FvwmPager) return; XTranslateCoordinates (dpy, Event.xbutton.window, Scr.Pager_w, Event.xbutton.x, Event.xbutton.y, &x, &y, &dumwin); width = Scr.FvwmPager->frame_width - 2*Scr.FvwmPager->boundary_width; height = Scr.FvwmPager->frame_height - Scr.FvwmPager->title_height - 2*Scr.FvwmPager->boundary_width; if(x<0)x=0; if(y<0)y=0; x = x * (Scr.VxMax+Scr.MyDisplayWidth)/width; y = y * (Scr.VyMax+Scr.MyDisplayHeight)/height; if(align) { x = (x/Scr.MyDisplayWidth)*Scr.MyDisplayWidth; y = (y/Scr.MyDisplayHeight)*Scr.MyDisplayHeight; } if(x<0)x=0; if(y<0)y=0; #ifndef NON_VIRTUAL MoveViewport(x,y,True); #endif if((ChangeFocus)&&(Scr.flags & ClickToFocus)) { tmp_win = FindCounterpart(Event.xbutton.subwindow); if(tmp_win) { RaiseWindow(tmp_win); SetFocus(tmp_win->w,tmp_win); ClearCirculatedFlag(); } } #endif } void RaiseWindow(FvwmWindow *t) { FvwmWindow *t2; int count, i; Window *wins; SetTimer(0); /* raise the target, at least */ count = 1; Broadcast(M_RAISE_WINDOW,3,t->w,t->frame,(unsigned long)t,0,0,0,0); for (t2 = Scr.FvwmRoot.next; t2 != NULL; t2 = t2->next) { if(t2->flags & ONTOP) count++; if((t2->flags & TRANSIENT) &&(t2->transientfor == t->w)&& (t2 != t)) { #ifndef NO_PAGER if((Scr.Pager_w)&& !(t2->flags & STICKY)) XRaiseWindow(dpy,t2->pager_view); #endif count++; Broadcast(M_RAISE_WINDOW,3,t2->w,t2->frame,(unsigned long) t2, 0,0,0,0); if ((t2->flags & ICONIFIED)&&(!(t2->flags & SUPPRESSICON))) { count += 2; } } } if ((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON))) { count += 2; } #ifndef NO_PAGER if((Scr.Pager_w)&& !(t->flags & STICKY)) { XRaiseWindow(dpy,t->pager_view); } #endif wins = (Window *)safemalloc(count*sizeof(Window)); i=0; /* ONTOP windows on top */ for (t2 = Scr.FvwmRoot.next; t2 != NULL; t2 = t2->next) { if(t2->flags & ONTOP) { Broadcast(M_RAISE_WINDOW,3,t2->w,t2->frame,(unsigned long) t2, 0,0,0,0); wins[i++] = t2->frame; } } /* now raise transients */ #ifndef DONT_RAISE_TRANSIENTS for (t2 = Scr.FvwmRoot.next; t2 != NULL; t2 = t2->next) { if((t2->flags & TRANSIENT) &&(t2->transientfor == t->w)&& (t2 != t)&&(!(t2->flags & ONTOP))) { wins[i++] = t2->frame; if ((t2->flags & ICONIFIED)&&(!(t2->flags & SUPPRESSICON))) { if(!(t2->flags & NOICON_TITLE))wins[i++] = t2->icon_w; wins[i++] = t2->icon_pixmap_w; } } } #endif if ((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON))) { if(!(t->flags & NOICON_TITLE))wins[i++] = t->icon_w; wins[i++] = t->icon_pixmap_w; } if(!(t->flags & ONTOP)) wins[i++] = t->frame; if(!(t->flags & ONTOP)) Scr.LastWindowRaised = t; if(i > 0) XRaiseWindow(dpy,wins[0]); XRestackWindows(dpy,wins,i); free(wins); RedrawPager(); #ifndef NON_VIRTUAL raisePanFrames(); #endif } void LowerWindow(FvwmWindow *t) { XLowerWindow(dpy,t->frame); SetTimer(0); Broadcast(M_LOWER_WINDOW,3,t->w,t->frame,(unsigned long)t,0,0,0,0); #ifndef NO_PAGER if((Scr.Pager_w)&& !(t->flags & STICKY)) XLowerWindow(dpy,t->pager_view); #endif if((t->flags & ICONIFIED)&&(!(t->flags & SUPPRESSICON))) { XLowerWindow(dpy, t->icon_w); XLowerWindow(dpy, t->icon_pixmap_w); } Scr.LastWindowRaised = (FvwmWindow *)0; #ifndef NO_PAGER if(Scr.CPagerWin) XLowerWindow(dpy,Scr.CPagerWin); #endif RedrawPager(); } void PagerMoveWindow() { #ifndef NO_PAGER FvwmWindow *tmp_win; unsigned int width, height; int Xoff,Yoff,x,y,MaxW,MaxH,xl,yt,xl1,yt1; Window target; Bool done,finished = False; /* I tried to implement a feature so that when windows which could be * opaque moved in a normal move would get the full size windows moved in * conjunction with the pager version of the window, but it seems to * be buggy on some machines */ #ifdef BROKEN_STUFF Bool OpaqueMove = False; int dwidth,dheight; #endif if(!Scr.FvwmPager) return; EnablePagerRedraw = False; target = Event.xbutton.subwindow; tmp_win = FindCounterpart(target); if(tmp_win == NULL) return; MaxW = Scr.VxMax + Scr.MyDisplayWidth; MaxH = Scr.VyMax + Scr.MyDisplayHeight; width = Scr.FvwmPager->frame_width - 2*Scr.FvwmPager->boundary_width; height = Scr.FvwmPager->frame_height - Scr.FvwmPager->title_height - 2*Scr.FvwmPager->boundary_width; XQueryPointer(dpy, target, &JunkRoot, &JunkChild, &JunkX, &JunkY, &Xoff, &Yoff, &JunkMask); XQueryPointer(dpy, Scr.Pager_w, &JunkRoot, &JunkChild, &JunkX, &JunkY, &xl, &yt, &JunkMask); if(xl<0)xl=0; if(yt<0)yt=0; if(xl>width)xl=width; if(yt>height)yt=height; xl -= Xoff; yt -= Yoff; xl1=xl; yt1=yt; while (!finished) { /* block until there is an interesting event */ XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | KeyPressMask | PointerMotionMask | ButtonMotionMask | ExposureMask | VisibilityChangeMask, &Event); StashEventTime(&Event); if (Event.type == MotionNotify) /* discard any extra motion events before a logical release */ while(XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask | ButtonRelease, &Event)) { StashEventTime(&Event); if(Event.type == ButtonRelease) break; } done = FALSE; /* Handle a limited number of key press events to allow mouseless * operation */ if(Event.type == KeyPress) Keyboard_shortcuts(&Event,ButtonRelease); switch(Event.type) { case ButtonPress: case KeyPress: /* throw away enter and leave events until release */ done = TRUE; break; case ButtonRelease: XQueryPointer(dpy, Scr.Pager_w, &JunkRoot, &JunkChild, &JunkX, &JunkY, &xl, &yt, &JunkMask); if(xl<0)xl=0; if(yt<0)yt=0; if(xl>width)xl=width; if(yt>height)yt=height; xl -= Xoff; yt -= Yoff; done = TRUE; finished = TRUE; break; case MotionNotify: XQueryPointer(dpy, Scr.Pager_w, &JunkRoot, &JunkChild, &JunkX, &JunkY, &xl, &yt, &JunkMask); if(xl<0)xl=0; if(yt<0)yt=0; if(xl>width)xl=width; if(yt>height)yt=height; /* redraw the rubberband */ xl -= Xoff; yt -= Yoff; done = TRUE; break; default: break; } if(!done) { DispatchEvent(); } XMoveWindow(dpy, target,xl, yt); DrawPartitionLines(); } x = xl*MaxW/(int)width - Scr.Vx; y = yt*MaxH/(int)height - Scr.Vy; MoveResizePagerView(tmp_win); if((xl1!=xl)||(yt1 != yt)) { if((tmp_win->flags & ICONIFIED)&&(!(tmp_win->flags & SUPPRESSICON))) { tmp_win->icon_x_loc = x; tmp_win->icon_xl_loc = x - (tmp_win->icon_w_width - tmp_win->icon_p_width)/2; tmp_win->icon_y_loc = y; XMoveWindow (dpy, tmp_win->icon_w, tmp_win->icon_xl_loc, y+tmp_win->icon_p_height); if(tmp_win->icon_pixmap_w != None) XMoveWindow (dpy, tmp_win->icon_pixmap_w, x,y); tmp_win->flags |= ICON_MOVED; } else { /* show the actual window */ SetupFrame(tmp_win,x,y, tmp_win->frame_width,tmp_win->frame_height,FALSE); } } EnablePagerRedraw = True; RedrawPager(); #endif } #ifndef NO_PAGER FvwmWindow *FindCounterpart(Window target) { FvwmWindow *t,*tmp_win=0; tmp_win = NULL; for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { if(t->pager_view == target) { tmp_win = t; } } return tmp_win; } #endif /*************************************************************************** * * 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) { #ifndef NON_VIRTUAL int x,y,total; #endif *delta_x = 0; *delta_y = 0; #ifndef NON_VIRTUAL if (DoHandlePageing) { if((Scr.ScrollResistance >= 10000)|| ((HorWarpSize ==0)&&(VertWarpSize==0))) return; /* need to move the viewport */ if(( *xl >= SCROLL_REGION)&&( *xl < Scr.MyDisplayWidth-SCROLL_REGION)&& ( *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( y= Scr.MyDisplayHeight-SCROLL_REGION) *delta_y = VertWarpSize; else *delta_y = 0; /* Ouch! lots of bounds checking */ if(Scr.Vx + *delta_x < 0) { if (!(Scr.flags & EdgeWrapX )) { *delta_x = -Scr.Vx; *xl = x - *delta_x; } else { *delta_x += Scr.VxMax + Scr.MyDisplayWidth; *xl = x + *delta_x % Scr.MyDisplayWidth + HorWarpSize; } } else if(Scr.Vx + *delta_x > Scr.VxMax) { if (!(Scr.flags & EdgeWrapX)) { *delta_x = Scr.VxMax - Scr.Vx; *xl = x - *delta_x; } else { *delta_x -= Scr.VxMax +Scr.MyDisplayWidth; *xl = x + *delta_x % Scr.MyDisplayWidth - HorWarpSize; } } else *xl = x - *delta_x; if(Scr.Vy + *delta_y < 0) { if (!(Scr.flags & EdgeWrapY)) { *delta_y = -Scr.Vy; *yt = y - *delta_y; } else { *delta_y += Scr.VyMax + Scr.MyDisplayHeight; *yt = y + *delta_y % Scr.MyDisplayHeight + VertWarpSize; } } else if(Scr.Vy + *delta_y > Scr.VyMax) { if (!(Scr.flags & EdgeWrapY)) { *delta_y = Scr.VyMax - Scr.Vy; *yt = y - *delta_y; } else { *delta_y -= Scr.VyMax + Scr.MyDisplayHeight; *yt = y + *delta_y % Scr.MyDisplayHeight - VertWarpSize; } } 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); } } #endif } void MoveResizeViewPortIndicator(void) { #ifndef NO_PAGER int width,height,x1,x2,y1,y2; if((Scr.CPagerWin)&&(Scr.FvwmPager)) { width = Scr.FvwmPager->frame_width - 2*Scr.FvwmPager->boundary_width; height = Scr.FvwmPager->frame_height - Scr.FvwmPager->title_height - 2*Scr.FvwmPager->boundary_width; x1 = Scr.Vx * width/(Scr.VxMax+Scr.MyDisplayWidth)+1; y1 = Scr.Vy * height/(Scr.VyMax+Scr.MyDisplayHeight)+1; x2 = (Scr.MyDisplayWidth) * width/(Scr.VxMax+Scr.MyDisplayWidth)-1; y2 = (Scr.MyDisplayHeight) * height/(Scr.VyMax+Scr.MyDisplayHeight)-1; if(x1==1) { x1--; x2++; } if(y1==1) { y1--; y2++; } XMoveResizeWindow(dpy,Scr.CPagerWin,x1,y1,x2,y2); } #endif } void MoveResizePagerView(FvwmWindow *t) { #ifndef NO_PAGER unsigned int width,height; int ww,wh; int wx,wy; int MaxH,MaxW; if((!Scr.FvwmPager)||(!pagerOn)) return; width = Scr.FvwmPager->frame_width - 2*Scr.FvwmPager->boundary_width; height = Scr.FvwmPager->frame_height - Scr.FvwmPager->title_height - 2*Scr.FvwmPager->boundary_width; MaxW = Scr.VxMax + Scr.MyDisplayWidth; MaxH = Scr.VyMax + Scr.MyDisplayHeight; if((!(t->flags & STICKY)&& (!(t->flags & ICONIFIED)||(!(t->flags & SUPPRESSICON)))&& (!(t->flags & ICONIFIED)||(!(t->flags & SUPPRESSICON))))&& (!((t->flags & ICONIFIED)&&(t->flags &ICON_UNMAPPED)))&& (t->Desk == Scr.CurrentDesk)) { if(t->flags & ICONIFIED) { /* show the icon loc */ wx = (t->icon_x_loc + Scr.Vx)*(int)width/MaxW;; wy = (t->icon_y_loc + Scr.Vy)*(int)height/MaxH; ww = t->icon_w_width*(int)width/MaxW; wh = (t->icon_w_height+t->icon_p_height)*(int)height/MaxH; } else { /* show the actual window */ wx = (t->frame_x + Scr.Vx)*(int)width/MaxW; wy = (t->frame_y + Scr.Vy)*(int)height/MaxH; ww = t->frame_width*(int)width/MaxW; wh = t->frame_height*(int)height/MaxH; } if(ww<2)ww=2; if(wh<2)wh=2; XMoveResizeWindow(dpy, t->pager_view, wx, wy, ww, wh); } else { /* window is sticky - make sure that the pager_view window is not * visible */ XMoveResizeWindow(dpy, t->pager_view, -10, -10, 5, 5); } RedrawPager(); #endif } /*********************************************************************** * * Procedure: * Initialize_pager - creates the pager window, if needed * * Inputs: * x,y location of the window * ***********************************************************************/ #ifndef NO_PAGER char *pager_name = "Fvwm Pager"; XSizeHints sizehints = { (PMinSize | PResizeInc | PBaseSize | PWinGravity), 0, 0, 100, 100, /* x, y, width and height */ 1, 1, /* Min width and height */ 0, 0, /* Max width and height */ 1, 1, /* Width and height increments */ {0, 0}, {0, 0}, /* Aspect ratio - not used */ 1, 1, /* base size */ (NorthWestGravity) /* gravity */ }; void initialize_pager(int x, int y) { XTextProperty name; int width,height,window_x,window_y; unsigned long valuemask; XSetWindowAttributes attributes; extern Pixel PagerBackColor; extern Pixel PagerForeColor; width = (Scr.VxMax + Scr.MyDisplayWidth)/Scr.VScale; height = (Scr.VyMax + Scr.MyDisplayHeight)/Scr.VScale; if(x >=0) window_x = x; else { sizehints.win_gravity = NorthEastGravity; window_x = Scr.MyDisplayWidth - width + x -2; } if(y >=0) window_y = y; else { window_y = Scr.MyDisplayHeight - height + y -2; if(x<0) sizehints.win_gravity = SouthEastGravity; else sizehints.win_gravity = SouthWestGravity; } valuemask = (CWBackPixel | CWBorderPixel | CWEventMask|CWCursor); attributes.background_pixel = PagerBackColor; attributes.border_pixel = Scr.StdColors.fore; attributes.cursor = Scr.FvwmCursors[DEFAULT]; attributes.event_mask = (ExposureMask | EnterWindowMask|ButtonReleaseMask| ButtonMotionMask); sizehints.width = width; sizehints.height = height; sizehints.x = window_x; sizehints.y = window_y; Scr.Pager_w = XCreateWindow (dpy, Scr.Root, window_x, window_y, width, height, (unsigned int) 1, CopyFromParent, InputOutput, (Visual *) CopyFromParent, valuemask, &attributes); XSetWMNormalHints(dpy,Scr.Pager_w,&sizehints); XStringListToTextProperty(&pager_name,1,&name); XSetWMName(dpy,Scr.Pager_w,&name); XSetWMIconName(dpy,Scr.Pager_w,&name); XFree((char *)name.value); attributes.event_mask = KeyPressMask | ExposureMask; attributes.background_pixel = PagerForeColor; attributes.cursor = Scr.FvwmCursors[DEFAULT]; Scr.CPagerWin=XCreateWindow(dpy,Scr.Pager_w,-10, -10, 10, 10,0, CopyFromParent, InputOutput,CopyFromParent, CWEventMask|CWBackPixel|CWCursor, &attributes); XMapRaised(dpy,Scr.CPagerWin); } #endif