/**************************************************************************** * This module is all new * by Rob Nation * * This code does smart-placement initial window placement stuff * * Copyright 1994 Robert Nation. No restrictions are placed on this code, * as long as the copyright notice is preserved . No guarantees or * warrantees of any sort whatsoever are given or implied or anything. ****************************************************************************/ #include "../configure.h" #include #include #include #include "fvwm.h" #include "menus.h" #include "misc.h" #include "parse.h" #include "screen.h" void SmartPlacement(FvwmWindow *t, int width, int height, int *x, int *y) { int temp_h,temp_w; int test_x = 0,test_y = 0; int loc_ok = False, tw,tx,ty,th; FvwmWindow *test_window; temp_h = height; temp_w = width; while(((test_y + temp_h) < (Scr.MyDisplayHeight))&&(!loc_ok)) { test_x = 0; while(((test_x + temp_w) < (Scr.MyDisplayWidth))&&(!loc_ok)) { loc_ok = True; test_window = Scr.FvwmRoot.next; while((test_window != (FvwmWindow *)0)&&(loc_ok == True)) { if(test_window->Desk == Scr.CurrentDesk) { if(Scr.flags & StubbornPlacement) { if((test_window->flags & ICONIFIED)&& (!(test_window->flags & ICON_UNMAPPED))&& (test_window->icon_w)&& (test_window != t)) { tw=test_window->icon_p_width; th=test_window->icon_p_height+ test_window->icon_w_height; tx = test_window->icon_x_loc; ty = test_window->icon_y_loc; if((tx<(test_x+width))&&((tx + tw) > test_x)&& (ty<(test_y+height))&&((ty + th)>test_y)) { loc_ok = False; test_x = tx + tw; } } } if(!(test_window->flags & ICONIFIED)&&(test_window != t)) { tw=test_window->frame_width+2*test_window->bw; th=test_window->frame_height+2*test_window->bw; tx = test_window->frame_x; ty = test_window->frame_y; if((tx <= (test_x+width))&&((tx + tw) >= test_x)&& (ty <= (test_y+height))&&((ty + th)>= test_y)) { loc_ok = False; test_x = tx + tw; } } } test_window = test_window->next; } test_x +=1; } test_y +=1; } if(loc_ok == False) { *x = -1; *y = -1; return; } *x = test_x; *y = test_y; } /************************************************************************** * * Handles initial placement and sizing of a new window * Returns False in the event of a lost window. * **************************************************************************/ Bool PlaceWindow(FvwmWindow *tmp_win, unsigned long tflag,int Desk) { FvwmWindow *t; int xl = -1,yt,DragWidth,DragHeight; int gravx, gravy; /* gravity signs for positioning */ extern Bool PPosOverride; GetGravityOffsets (tmp_win, &gravx, &gravy); /* Select a desk to put the window on (in list of priority): * 1. Sticky Windows stay on the current desk. * 2. Windows specified with StartsOnDesk go where specified * 3. Put it on the desk it was on before the restart. * 4. Transients go on the same desk as their parents. * 5. Window groups stay together (completely untested) */ tmp_win->Desk = Scr.CurrentDesk; if (tflag & STICKY_FLAG) tmp_win->Desk = Scr.CurrentDesk; else if (tflag & STAYSONDESK_FLAG) tmp_win->Desk = Desk; else { Atom atype; int aformat; unsigned long nitems, bytes_remain; unsigned char *prop; if((tmp_win->wmhints)&&(tmp_win->wmhints->flags & WindowGroupHint)&& (tmp_win->wmhints->window_group != None)&& (tmp_win->wmhints->window_group != Scr.Root)) { /* Try to find the group leader or another window * in the group */ for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { if((t->w == tmp_win->wmhints->window_group)|| ((t->wmhints)&&(t->wmhints->flags & WindowGroupHint)&& (t->wmhints->window_group==tmp_win->wmhints->window_group))) tmp_win->Desk = t->Desk; } } if((tmp_win->flags & TRANSIENT)&&(tmp_win->transientfor!=None)&& (tmp_win->transientfor != Scr.Root)) { /* Try to find the parent's desktop */ for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { if(t->w == tmp_win->transientfor) tmp_win->Desk = t->Desk; } } if ((XGetWindowProperty(dpy, tmp_win->w, _XA_WM_DESKTOP, 0L, 1L, True, _XA_WM_DESKTOP, &atype, &aformat, &nitems, &bytes_remain, &prop))==Success) { if(prop != NULL) { tmp_win->Desk = *(unsigned long *)prop; XFree(prop); } } } /* I think it would be good to switch to the selected desk * whenever a new window pops up, except during initialization */ if(!PPosOverride) changeDesks(0,tmp_win->Desk); /* Desk has been selected, now pick a location for the window */ /* * If * o the window is a transient, or * * o a USPosition was requested * * then put the window where requested. * * If RandomPlacement was specified, * then place the window in a psuedo-random location */ if (!(tmp_win->flags & TRANSIENT) && !(tmp_win->hints.flags & USPosition) && ((Scr.flags & NoPPosition)||!(tmp_win->hints.flags & PPosition)) && !(PPosOverride) && !((tmp_win->wmhints)&& (tmp_win->wmhints->flags & StateHint)&& (tmp_win->wmhints->initial_state == IconicState)) ) { /* Get user's window placement, unless RandomPlacement is specified */ if(Scr.flags & RandomPlacement) { if(Scr.flags & SMART_PLACEMENT) SmartPlacement(tmp_win,tmp_win->frame_width+2*tmp_win->bw, tmp_win->frame_height+2*tmp_win->bw, &xl,&yt); if(xl < 0) { /* plase window in a random location */ if ((Scr.randomx += Scr.TitleHeight) > Scr.MyDisplayWidth / 2) Scr.randomx = Scr.TitleHeight; if ((Scr.randomy += 2*Scr.TitleHeight) > Scr.MyDisplayHeight / 2) Scr.randomy = 2 * Scr.TitleHeight; tmp_win->attr.x = Scr.randomx - tmp_win->old_bw; tmp_win->attr.y = Scr.randomy - tmp_win->old_bw; } else { tmp_win->attr.x = xl - tmp_win->old_bw; tmp_win->attr.y = yt - tmp_win->old_bw; } /* patches 11/93 to try to keep the window on the * screen */ tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->bw; tmp_win->frame_y = tmp_win->attr.y + tmp_win->old_bw - tmp_win->bw; if(tmp_win->frame_x + tmp_win->frame_width + 2*tmp_win->boundary_width> Scr.MyDisplayWidth) { tmp_win->attr.x = Scr.MyDisplayWidth -tmp_win->attr.width - tmp_win->old_bw +tmp_win->bw - 2*tmp_win->boundary_width; Scr.randomx = 0; } if(tmp_win->frame_y + 2*tmp_win->boundary_width+tmp_win->title_height + tmp_win->frame_height > Scr.MyDisplayHeight) { tmp_win->attr.y = Scr.MyDisplayHeight -tmp_win->attr.height - tmp_win->old_bw +tmp_win->bw - tmp_win->title_height - 2*tmp_win->boundary_width;; Scr.randomy = 0; } tmp_win->xdiff = tmp_win->attr.x - tmp_win->bw; tmp_win->ydiff = tmp_win->attr.y - tmp_win->bw; } else { xl = -1; yt = -1; if(Scr.flags & SMART_PLACEMENT) SmartPlacement(tmp_win,tmp_win->frame_width+2*tmp_win->bw, tmp_win->frame_height+2*tmp_win->bw, &xl,&yt); if(xl < 0) { if(GrabEm(POSITION)) { /* Grabbed the pointer - continue */ XGrabServer(dpy); if(XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY, (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW, &JunkDepth) == 0) { free((char *)tmp_win); XUngrabServer(dpy); return False; } DragWidth += 2*tmp_win->boundary_width; DragHeight += tmp_win->title_height + 2*tmp_win->boundary_width; XMapRaised(dpy,Scr.SizeWindow); moveLoop(tmp_win,0,0,DragWidth,DragHeight, &xl,&yt,False,True); XUnmapWindow(dpy,Scr.SizeWindow); XUngrabServer(dpy); UngrabEm(); } else { /* couldn't grab the pointer - better do something */ XBell(dpy,Scr.screen); xl = 0; yt = 0; } } tmp_win->attr.y = yt - tmp_win->old_bw + tmp_win->bw; tmp_win->attr.x = xl - tmp_win->old_bw + tmp_win->bw; tmp_win->xdiff = xl ; tmp_win->ydiff = yt ; } } else { /* the USPosition was specified, or the window is a transient, * or it starts iconic so place it automatically */ tmp_win->xdiff = tmp_win->attr.x; tmp_win->ydiff = tmp_win->attr.y; /* put it where asked, mod title bar */ /* if the gravity is towards the top, move it by the title height */ tmp_win->attr.y -= gravy*(tmp_win->bw-tmp_win->old_bw); tmp_win->attr.x -= gravx*(tmp_win->bw-tmp_win->old_bw); if(gravy > 0) tmp_win->attr.y -= 2*tmp_win->boundary_width + tmp_win->title_height; if(gravx > 0) tmp_win->attr.x -= 2*tmp_win->boundary_width; } return True; } /************************************************************************ * * Procedure: * GetGravityOffsets - map gravity to (x,y) offset signs for adding * to x and y when window is mapped to get proper placement. * ************************************************************************/ struct _gravity_offset { int x, y; }; void GetGravityOffsets (FvwmWindow *tmp,int *xp,int *yp) { static struct _gravity_offset gravity_offsets[11] = { { 0, 0 }, /* ForgetGravity */ { -1, -1 }, /* NorthWestGravity */ { 0, -1 }, /* NorthGravity */ { 1, -1 }, /* NorthEastGravity */ { -1, 0 }, /* WestGravity */ { 0, 0 }, /* CenterGravity */ { 1, 0 }, /* EastGravity */ { -1, 1 }, /* SouthWestGravity */ { 0, 1 }, /* SouthGravity */ { 1, 1 }, /* SouthEastGravity */ { 0, 0 }, /* StaticGravity */ }; register int g = ((tmp->hints.flags & PWinGravity) ? tmp->hints.win_gravity : NorthWestGravity); if (g < ForgetGravity || g > StaticGravity) *xp = *yp = 0; else { *xp = (int)gravity_offsets[g].x; *yp = (int)gravity_offsets[g].y; } return; }