/** Set a client's sticky status. This will update transients. */ void SetClientSticky(ClientNode *np, char isSticky) { ClientNode *tp; int x; char old; Assert(np); /* Get the old sticky status. */ if(np->state.status & STAT_STICKY) { old = 1; } else { old = 0; } if(isSticky && !old) { /* Change from non-sticky to sticky. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp == np || tp->owner == np->window) { tp->state.status |= STAT_STICKY; SetCardinalAtom(tp->window, ATOM_NET_WM_DESKTOP, ~0UL); WriteState(tp); } } } } else if(!isSticky && old) { /* Change from sticky to non-sticky. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp == np || tp->owner == np->window) { tp->state.status &= ~STAT_STICKY; WriteState(tp); } } } /* Since this client is no longer sticky, we need to assign * a desktop. Here we use the current desktop. * Note that SetClientDesktop updates transients (which is good). */ SetClientDesktop(np, currentDesktop); } }
/*! * This function saves the current window position and size using the base * class persist method. Minimized and maximized state is also optionally * preserved. * @sa CResizableState::WriteState * @note Window coordinates are in the form used by the system functions * GetWindowPlacement and SetWindowPlacement. * * @param pszName String that identifies stored settings * @param bRectOnly Flag that specifies wether to ignore min/max state * * @return Returns @a TRUE if successful, @a FALSE otherwise */ BOOL CResizableWndState::SaveWindowRect(LPCTSTR pszName, BOOL bRectOnly) { CString data, id; WINDOWPLACEMENT wp; SecureZeroMemory(&wp, sizeof(WINDOWPLACEMENT)); wp.length = sizeof(WINDOWPLACEMENT); if (!GetResizableWnd()->GetWindowPlacement(&wp)) return FALSE; // use workspace coordinates RECT& rc = wp.rcNormalPosition; if (bRectOnly) // save size/pos only (normal state) { data.Format(PLACEMENT_FMT, rc.left, rc.top, rc.right, rc.bottom, SW_SHOWNORMAL, 0, 0, 0); } else // save also min/max state { data.Format(PLACEMENT_FMT, rc.left, rc.top, rc.right, rc.bottom, wp.showCmd, wp.flags, wp.ptMinPosition.x, wp.ptMinPosition.y); } id = CString(pszName) + PLACEMENT_ENT; return WriteState(id, data); }
/*---------------------------------------------------------------------*/ BOOL ArchiveClose(H_ARCHIVE harchive) { NODE *node; STREAM *stream; if (!ValidateHandle(harchive)) return (FALSE); _archive[harchive].last_error = ARC_NO_ERROR; _archive_error = ARC_NO_ERROR; ArchiveLog(ARC_LOG_VERBOSE, "Close archive: %s", _archive[harchive].path); /* Close all open event files on archive... */ if ((node = FirstNode(&_archive[harchive].streams))) { do { stream = (STREAM *) node->data; if (_archive[harchive].access == ARC_WRITE) CloseEventFileAndRename(harchive, stream); else CloseEventFile(stream); } while ((node = NextNode(node)) != NULL); } /* If open for write... */ if (_archive[harchive].access == ARC_WRITE) { MUTEX_LOCK(&_archive[harchive].purge.mutex); if(_archive[harchive].purge.active ) { _archive[harchive].purge.stop = TRUE; MUTEX_UNLOCK(&_archive[harchive].purge.mutex); ArchiveLog(ARC_LOG_VERBOSE, "Stopping purge thread"); SEM_POST(&_archive[harchive].purge.semaphore); THREAD_JOIN(&_archive[harchive].purge.thread_id); } else MUTEX_UNLOCK(&_archive[harchive].purge.mutex); /* Mark as closed and write state to disk */ _archive[harchive].state.write = FALSE; if (!WriteState(harchive)) return (FALSE); } /* Close the state file */ if (!FileClose(_archive[harchive].file)) { _archive[harchive].last_error = ARC_FILE_IO_ERROR; return (FALSE); } _n_archives--; /* Clear state */ MUTEX_DESTROY(&_archive[harchive].mutex); DestroyList(&_archive[harchive].streams); DestroyPurge(&_archive[harchive].purge); InitArchive(harchive); return (TRUE); }
/** Set a client's state to withdrawn. */ void SetClientWithdrawn(ClientNode *np) { Assert(np); if(activeClient == np) { activeClient = NULL; np->state.status &= ~STAT_ACTIVE; FocusNextStacked(np); } if(np->state.status & STAT_MAPPED) { UnmapClient(np); if(np->parent != None) { JXUnmapWindow(display, np->parent); } } else if(np->state.status & STAT_SHADED) { if(!(np->state.status & STAT_MINIMIZED)) { if(np->parent != None) { JXUnmapWindow(display, np->parent); } } } np->state.status &= ~STAT_SHADED; np->state.status &= ~STAT_MINIMIZED; np->state.status &= ~STAT_SDESKTOP; WriteState(np); RequireTaskUpdate(); RequirePagerUpdate(); }
/** Handle an unmap notify event. */ void HandleUnmapNotify(const XUnmapEvent *event) { ClientNode *np; XEvent e; Assert(event); np = FindClientByWindow(event->window); if(np && np->window == event->window) { if(JXCheckTypedWindowEvent(display, np->window, DestroyNotify, &e)) { HandleDestroyNotify(&e.xdestroywindow); return; } if(np->controller) { (np->controller)(1); } if(np->state.status & STAT_MAPPED) { np->state.status &= ~STAT_MAPPED; JXUnmapWindow(display, np->parent); WriteState(np); UpdateTaskBar(); UpdatePager(); } } }
/* ** A "local" function of KeepState(). Enters #name# marked with #seqNo# into ** the state file (global) #journalPath#. Used to keep a log of all writes ** performed by the memory. Returns 1 if successful, else 0. */ static int EnterInJournal(const char *name, double seqNo) { char journalRec[MAX_RECORD_SIZE]; double now; memset(journalRec, 0, sizeof(journalRec)); now = CurrentTime(); if(sprintf(journalRec,"%10.0f %64s", seqNo, name) < 2) { FAIL1("EnterInJournal: write failed, errno %d\n", errno); } if(!WriteState(journalPath, journalFileSize, KEEP_A_LONG_TIME, now, journalRec, strlen(journalRec))) { FAIL("EnterInJournal: write state failed\n"); } return(1); }
/** Minimize all transients as well as the specified client. */ void MinimizeTransients(ClientNode *np, char lower) { ClientNode *tp; int x; Assert(np); /* Unmap the window and update its state. */ if(np->state.status & (STAT_MAPPED | STAT_SHADED)) { UnmapClient(np); if(np->parent != None) { JXUnmapWindow(display, np->parent); } } np->state.status |= STAT_MINIMIZED; /* Minimize transient windows. */ for(x = 0; x < LAYER_COUNT; x++) { tp = nodes[x]; while(tp) { ClientNode *next = tp->next; if(tp->owner == np->window && (tp->state.status & (STAT_MAPPED | STAT_SHADED)) && !(tp->state.status & STAT_MINIMIZED)) { MinimizeTransients(tp, lower); } tp = next; } } /* Focus the next window. */ if(np->state.status & STAT_ACTIVE) { FocusNextStacked(np); } if(lower) { /* Move this client to the end of the layer list. */ if(nodeTail[np->state.layer] != np) { if(np->prev) { np->prev->next = np->next; } else { nodes[np->state.layer] = np->next; } np->next->prev = np->prev; tp = nodeTail[np->state.layer]; nodeTail[np->state.layer] = np; tp->next = np; np->prev = tp; np->next = NULL; } } WriteState(np); }
/** Set the client layer. This will affect transients. */ void SetClientLayer(ClientNode *np, unsigned int layer) { ClientNode *tp, *next; Assert(np); Assert(layer <= LAST_LAYER); if(np->state.layer != layer) { int x; /* Loop through all clients so we get transients. */ for(x = FIRST_LAYER; x <= LAST_LAYER; x++) { tp = nodes[x]; while(tp) { next = tp->next; if(tp == np || tp->owner == np->window) { /* Remove from the old node list */ if(next) { next->prev = tp->prev; } else { nodeTail[tp->state.layer] = tp->prev; } if(tp->prev) { tp->prev->next = next; } else { nodes[tp->state.layer] = next; } /* Insert into the new node list */ tp->prev = NULL; tp->next = nodes[layer]; if(nodes[layer]) { nodes[layer]->prev = tp; } else { nodeTail[layer] = tp; } nodes[layer] = tp; /* Set the new layer */ tp->state.layer = layer; WriteState(tp); } tp = next; } } RequireRestack(); } }
bool WorldSimulation::WriteState(string& s) const { File f; if(!f.OpenData()) return false; if(!WriteState(f)) return false; const char* buf = (const char*)f.GetDataBuffer(); //HACK for File internal buffer length bug returning buffer capacity rather //than size //int len = f.Length(); int len = f.Position(); s.resize(len); for(int i=0;i<len;i++) s[i] = buf[i]; return true; }
/*---------------------------------------------------------------------*/ BOOL OpenStateForWrite(H_ARCHIVE harchive) { _archive[harchive].last_error = ARC_NO_ERROR; _archive_error = ARC_NO_ERROR; /* Create filespec for state file and open for read */ sprintf(_archive[harchive].filespec, "%s%c%s", _archive[harchive].path, PATH_DELIMITER, STATE_FILENAME); if ((_archive[harchive].file = FileOpenForRead(_archive[harchive].filespec)) == VOID_H_FILE) { ArchiveLog(ARC_LOG_ERRORS, "OpenStateForWrite: Error opening state file: %s", _archive[harchive].filespec); _archive[harchive].last_error = ARC_FILE_IO_ERROR; return (FALSE); } /* Read the current state */ if (!ReadState(harchive)) return (FALSE); if (_archive[harchive].state.write) { ArchiveLog(ARC_LOG_ERRORS, "OpenStateForWrite: Archive is open for write by another process: %s", _archive[harchive].path); _archive[harchive].last_error = ARC_PERMISSION_DENIED; return (FALSE); } if (!FileClose(_archive[harchive].file)) { _archive[harchive].last_error = ARC_FILE_IO_ERROR; return (FALSE); } /* Reopen for write */ if ((_archive[harchive].file = FileOpenForWrite(_archive[harchive].filespec)) == VOID_H_FILE) { ArchiveLog(ARC_LOG_ERRORS, "OpenStateForWrite: Error opening state file: %s", _archive[harchive].filespec); _archive[harchive].last_error = ARC_FILE_IO_ERROR; return (FALSE); } /* Mark as open for write */ _archive[harchive].state.write = TRUE; /* Archive is open for read-write access */ _archive[harchive].access = ARC_WRITE; /* Start the update timer */ Timer48Start(&_archive[harchive].update, 0); if (!WriteState(harchive)) return (FALSE); /* Start the update timer */ Timer48Start(&_archive[harchive].update, UPDATE_INTERVAL); ArchiveLog(ARC_LOG_MAXIMUM, "State file opened for write: %s", _archive[harchive].filespec); return (TRUE); }
void BodyParticleSystem::RunSimulation() { Initialize(); InitializeOpenCL(); PutParticles(config.particle_count, hposold, hvelold); const std::string& configFilename = config.getConfigParser().getFilename(); const std::string& pathPrefix = configFilename.substr(0, configFilename.find_last_of('.')); if (mkdir(pathPrefix.c_str(), 0755) == -1) { std::cout << "Could not create directory '" << pathPrefix << "', exiting." << std::endl; exit(EXIT_FAILURE); } std::cout.precision(8); std::cout << std::fixed; time_t c0, c1; time(&c0); int it = 0; WriteState(pathPrefix, it); // write initial state for(it = 1; it <= config.step_count; ++it) // main propagation loop { PropagateStep(); if ((it) % config.output_step_count == 0) { WriteState(pathPrefix, it); // output current statistics auto avg_s = std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(stats.average()); std::cout << "Average OpenCL kernel runtime per iteration: " << avg_s.count() << " s" << std::endl; } } // NOTE: no final write, to have only equidistant simulation time intervalls between output values time(&c1); fprintf(stderr, "Simulation for %d particles over %d steps took %.0f s\n", config.particle_count, config.step_count, difftime(c1, c0)); }
/** Shade a client. */ void ShadeClient(ClientNode *np) { Assert(np); if((np->state.status & (STAT_SHADED | STAT_FULLSCREEN)) || !(np->state.border & BORDER_SHADE)) { return; } UnmapClient(np); np->state.status |= STAT_SHADED; WriteState(np); ResetBorder(np); RequirePagerUpdate(); }
/** Restore a window with its transients (helper method). */ void RestoreTransients(ClientNode *np, char raise) { ClientNode *tp; int x; Assert(np); /* Make sure this window is on the current desktop. */ SetClientDesktop(np, currentDesktop); /* Restore this window. */ if(!(np->state.status & STAT_MAPPED)) { if(np->state.status & STAT_SHADED) { if(np->parent != None) { JXMapWindow(display, np->parent); } } else { JXMapWindow(display, np->window); if(np->parent != None) { JXMapWindow(display, np->parent); } np->state.status |= STAT_MAPPED; } } np->state.status &= ~STAT_MINIMIZED; np->state.status &= ~STAT_SDESKTOP; /* Restore transient windows. */ for(x = 0; x < LAYER_COUNT; x++) { for(tp = nodes[x]; tp; tp = tp->next) { if(tp->owner == np->window && (tp->state.status & STAT_MINIMIZED)) { RestoreTransients(tp, raise); } } } if(raise) { FocusClient(np); RaiseClient(np); } WriteState(np); }
/** Handle an unmap notify event. */ void HandleUnmapNotify(const XUnmapEvent *event) { ClientNode *np; XEvent e; Assert(event); if(event->window != event->event) { /* Allow ICCCM synthetic UnmapNotify events through. */ if (event->event != rootWindow || !event->send_event) { return; } } np = FindClientByWindow(event->window); if(np) { /* Grab the server to prevent the client from destroying the * window after we check for a DestroyNotify. */ GrabServer(); if(np->controller) { (np->controller)(1); } if(JXCheckTypedWindowEvent(display, np->window, DestroyNotify, &e)) { UpdateTime(&e); RemoveClient(np); } else if((np->state.status & STAT_MAPPED) || event->send_event) { if(!(np->state.status & STAT_HIDDEN)) { np->state.status &= ~STAT_MAPPED; JXUngrabButton(display, AnyButton, AnyModifier, np->window); GravitateClient(np, 1); JXReparentWindow(display, np->window, rootWindow, np->x, np->y); WriteState(np); JXRemoveFromSaveSet(display, np->window); RemoveClient(np); } } UngrabServer(); } }
/** Maximize a client window. */ void MaximizeClient(ClientNode *np, MaxFlags flags) { /* Return if we don't have a client. */ if(np == NULL) { return; } /* Don't allow maximization of full-screen clients. */ if(np->state.status & STAT_FULLSCREEN) { return; } if(!(np->state.border & BORDER_MAX)) { return; } if(np->state.status & STAT_SHADED) { UnshadeClient(np); } RaiseClient(np); FocusClient(np); if(np->state.maxFlags) { /* Undo existing maximization. */ np->x = np->oldx; np->y = np->oldy; np->width = np->oldWidth; np->height = np->oldHeight; np->state.maxFlags = MAX_NONE; } if(flags != MAX_NONE) { /* Maximize if requested. */ PlaceMaximizedClient(np, flags); } WriteState(np); ResetBorder(np); DrawBorder(np); SendConfigureEvent(np); RequirePagerUpdate(); }
/** Handle a map request. */ void HandleMapRequest(const XMapEvent *event) { ClientNode *np; Assert(event); if(CheckSwallowMap(event->window)) { return; } np = FindClientByWindow(event->window); if(!np) { GrabServer(); np = AddClientWindow(event->window, 0, 1); if(np) { if(!(np->state.status & STAT_NOFOCUS)) { FocusClient(np); } } else { JXMapWindow(display, event->window); } UngrabServer(); } else { if(!(np->state.status & STAT_MAPPED)) { UpdateState(np); np->state.status |= STAT_MAPPED; XMapWindow(display, np->window); if(np->parent != None) { XMapWindow(display, np->parent); } if(!(np->state.status & STAT_STICKY)) { np->state.desktop = currentDesktop; } if(!(np->state.status & STAT_NOFOCUS)) { FocusClient(np); RaiseClient(np); } WriteState(np); RequireTaskUpdate(); RequirePagerUpdate(); } } RequireRestack(); }
/*! * This function saves the current property sheet active page using the base * class persist method. * @sa CResizableState::WriteState * * @param pszName String that identifies stored settings * * @return Returns @a TRUE if successful, @a FALSE otherwise */ BOOL CResizableSheetState::SavePage(LPCTSTR pszName) { // saves active page index, or the initial page if problems // cannot use GetActivePage, because it always fails CPropertySheet* pSheet = DYNAMIC_DOWNCAST(CPropertySheet, GetResizableWnd()); if (pSheet == NULL) return FALSE; int page = pSheet->m_psh.nStartPage; CTabCtrl *pTab = pSheet->GetTabControl(); if (pTab != NULL) page = pTab->GetCurSel(); if (page < 0) page = pSheet->m_psh.nStartPage; CString data, id; _itot(page, data.GetBuffer(10), 10); id = CString(pszName) + ACTIVEPAGE_ENT; return WriteState(id, data); }
/** Unshade a client. */ void UnshadeClient(ClientNode *np) { Assert(np); if(!(np->state.status & STAT_SHADED)) { return; } if(!(np->state.status & (STAT_MINIMIZED | STAT_SDESKTOP))) { JXMapWindow(display, np->window); np->state.status |= STAT_MAPPED; } np->state.status &= ~STAT_SHADED; WriteState(np); ResetBorder(np); RefocusClient(); RequirePagerUpdate(); }
/*---------------------------------------------------------------------*/ BOOL ArchiveSync(H_ARCHIVE harchive) { FILE_STAT stat; if (!ValidateHandle(harchive)) return (FALSE); _archive[harchive].last_error = ARC_NO_ERROR; _archive_error = ARC_NO_ERROR; /* If we're open for write and the update timer has expired... */ if (_archive[harchive].access == ARC_WRITE) { if (_archive[harchive].dirty) { if (!Timer48Expired(&_archive[harchive].update)) return (TRUE); ArchiveLog(ARC_LOG_MAXIMUM, "Synchronize state file for write"); if (!WriteState(harchive)) return (FALSE); _archive[harchive].dirty = FALSE; } /* Restart the update timer */ Timer48Restart(&_archive[harchive].update); } /* If we're open for read... */ else if (_archive[harchive].access == ARC_READ) { /* If the state file has changed since we last looked... */ if (!GetFileStat(_archive[harchive].filespec, &stat)) return (FALSE); if (memcmp(&_archive[harchive].stat, &stat, sizeof(FILE_STAT)) != 0) { ArchiveLog(ARC_LOG_VERBOSE, "State file has changed, synchronizing"); if (!ReadState(harchive)) return (FALSE); } } else return (FALSE); return (TRUE); }
/** Handle a _NET_MOVERESIZE_WINDOW request. */ void HandleNetMoveResize(const XClientMessageEvent *event, ClientNode *np) { long flags, gravity; long x, y; long width, height; int deltax, deltay; int north, south, east, west; Assert(event); Assert(np); gravity = event->data.l[0] & 0xFF; flags = event->data.l[0] >> 8; x = np->x; y = np->y; width = np->width; height = np->height; if(flags & (1 << 0)) { x = event->data.l[1]; } if(flags & (1 << 1)) { y = event->data.l[2]; } if(flags & (1 << 2)) { width = event->data.l[3]; } if(flags & (1 << 3)) { height = event->data.l[4]; } if(gravity == 0) { gravity = np->gravity; } GetBorderSize(np, &north, &south, &east, &west); GetGravityDelta(np, &deltax, &deltay); x -= deltax; y -= deltay; np->x = x; np->y = y; np->width = width; np->height = height; if(np->state.status & STAT_FULLSCREEN) { Warning("Fullscreen state will be shaped!"); } /** Reset shaped bound */ ResetRoundedRectWindow(np->parent); ShapeRoundedRectWindow(np->parent, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); WriteState(np); SendConfigureEvent(np); }
/** Handle a property notify event. */ char HandlePropertyNotify(const XPropertyEvent *event) { ClientNode *np = FindClientByWindow(event->window); if(np) { char changed = 0; switch(event->atom) { case XA_WM_NAME: ReadWMName(np); changed = 1; break; case XA_WM_NORMAL_HINTS: ReadWMNormalHints(np); if(ConstrainSize(np)) { ResetBorder(np); } changed = 1; break; case XA_WM_HINTS: if(np->state.status & STAT_URGENT) { UnregisterCallback(SignalUrgent, np); } ReadWMHints(np->window, &np->state, 1); if(np->state.status & STAT_URGENT) { RegisterCallback(URGENCY_DELAY, SignalUrgent, np); } WriteState(np); break; case XA_WM_TRANSIENT_FOR: JXGetTransientForHint(display, np->window, &np->owner); break; case XA_WM_ICON_NAME: case XA_WM_CLIENT_MACHINE: break; default: if(event->atom == atoms[ATOM_WM_COLORMAP_WINDOWS]) { ReadWMColormaps(np); UpdateClientColormap(np); } else if(event->atom == atoms[ATOM_WM_PROTOCOLS]) { ReadWMProtocols(np->window, &np->state); } else if(event->atom == atoms[ATOM_NET_WM_ICON]) { LoadIcon(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_NAME]) { ReadWMName(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_STRUT_PARTIAL]) { ReadClientStrut(np); } else if(event->atom == atoms[ATOM_NET_WM_STRUT]) { ReadClientStrut(np); } else if(event->atom == atoms[ATOM_MOTIF_WM_HINTS]) { UpdateState(np); WriteState(np); ResetBorder(np); changed = 1; } else if(event->atom == atoms[ATOM_NET_WM_WINDOW_OPACITY]) { ReadWMOpacity(np->window, &np->state.opacity); if(np->parent != None) { SetOpacity(np, np->state.opacity, 1); } } break; } if(changed) { DrawBorder(np); RequireTaskUpdate(); RequirePagerUpdate(); } if(np->state.status & STAT_WMDIALOG) { return 0; } else { return 1; } } return 1; }
/** Add a window to management. */ ClientNode *AddClientWindow(Window w, char alreadyMapped, char notOwner) { XWindowAttributes attr; ClientNode *np; Assert(w != None); /* Get window attributes. */ if(JXGetWindowAttributes(display, w, &attr) == 0) { return NULL; } /* Determine if we should care about this window. */ if(attr.override_redirect == True) { return NULL; } if(attr.class == InputOnly) { return NULL; } /* Prepare a client node for this window. */ np = Allocate(sizeof(ClientNode)); memset(np, 0, sizeof(ClientNode)); np->window = w; np->owner = None; np->state.desktop = currentDesktop; np->x = attr.x; np->y = attr.y; np->width = attr.width; np->height = attr.height; np->cmap = attr.colormap; np->state.status = STAT_NONE; np->state.maxFlags = MAX_NONE; np->state.layer = LAYER_NORMAL; np->state.defaultLayer = LAYER_NORMAL; np->state.border = BORDER_DEFAULT; np->borderAction = BA_NONE; ReadClientInfo(np, alreadyMapped); if(!notOwner) { np->state.border = BORDER_OUTLINE | BORDER_TITLE | BORDER_MOVE; np->state.status |= STAT_WMDIALOG | STAT_STICKY; np->state.layer = LAYER_ABOVE; np->state.defaultLayer = LAYER_ABOVE; } ApplyGroups(np); if(np->icon == NULL) { LoadIcon(np); } /* We now know the layer, so insert */ np->prev = NULL; np->next = nodes[np->state.layer]; if(np->next) { np->next->prev = np; } else { nodeTail[np->state.layer] = np; } nodes[np->state.layer] = np; SetDefaultCursor(np->window); ReparentClient(np, notOwner); PlaceClient(np, alreadyMapped); if(!((np->state.status & STAT_FULLSCREEN) || np->state.maxFlags)) { int north, south, east, west; GetBorderSize(&np->state, &north, &south, &east, &west); if(np->parent != None) { JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); } else { JXMoveResizeWindow(display, np->window, np->x, np->y, np->width, np->height); } } /* If one of these fails we are SOL, so who cares. */ XSaveContext(display, np->window, clientContext, (void*)np); if(np->parent != None) { XSaveContext(display, np->parent, frameContext, (void*)np); } if(np->state.status & STAT_MAPPED) { JXMapWindow(display, np->window); if(np->parent != None) { JXMapWindow(display, np->parent); } } clientCount += 1; if(!alreadyMapped) { RaiseClient(np); } if(np->state.status & STAT_OPACITY) { SetOpacity(np, np->state.opacity, 1); } else { SetOpacity(np, settings.inactiveClientOpacity, 1); } if(np->state.status & STAT_STICKY) { SetCardinalAtom(np->window, ATOM_NET_WM_DESKTOP, ~0UL); } else { SetCardinalAtom(np->window, ATOM_NET_WM_DESKTOP, np->state.desktop); } /* Shade the client if requested. */ if(np->state.status & STAT_SHADED) { np->state.status &= ~STAT_SHADED; ShadeClient(np); } /* Minimize the client if requested. */ if(np->state.status & STAT_MINIMIZED) { np->state.status &= ~STAT_MINIMIZED; MinimizeClient(np, 0); } /* Maximize the client if requested. */ if(np->state.maxFlags) { const MaxFlags flags = np->state.maxFlags; np->state.maxFlags = MAX_NONE; MaximizeClient(np, flags); } if(np->state.status & STAT_URGENT) { RegisterCallback(URGENCY_DELAY, SignalUrgent, np); } /* Update task bars. */ AddClientToTaskBar(np); /* Make sure we're still in sync */ WriteState(np); SendConfigureEvent(np); /* Hide the client if we're not on the right desktop. */ if(np->state.desktop != currentDesktop && !(np->state.status & STAT_STICKY)) { HideClient(np); } ReadClientStrut(np); /* Focus transients if their parent has focus. */ if(np->owner != None) { if(activeClient && np->owner == activeClient->window) { FocusClient(np); } } /* Make the client fullscreen if requested. */ if(np->state.status & STAT_FULLSCREEN) { np->state.status &= ~STAT_FULLSCREEN; SetClientFullScreen(np, 1); } ResetBorder(np); return np; }
/** Handle a _NET_WM_STATE request. */ void HandleNetWMState(const XClientMessageEvent *event, ClientNode *np) { unsigned int x; MaxFlags maxFlags; char actionStick; char actionShade; char actionFullScreen; char actionMinimize; char actionNolist; char actionNopager; char actionBelow; char actionAbove; /* Up to two actions to be applied together. */ maxFlags = MAX_NONE; actionStick = 0; actionShade = 0; actionFullScreen = 0; actionMinimize = 0; actionNolist = 0; actionNopager = 0; actionBelow = 0; actionAbove = 0; for(x = 1; x <= 2; x++) { if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_STICKY]) { actionStick = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT]) { maxFlags |= MAX_VERT; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) { maxFlags |= MAX_HORIZ; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_SHADED]) { actionShade = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_FULLSCREEN]) { actionFullScreen = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_HIDDEN]) { actionMinimize = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR]) { actionNolist = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_SKIP_PAGER]) { actionNopager = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_BELOW]) { actionBelow = 1; } else if(event->data.l[x] == (long)atoms[ATOM_NET_WM_STATE_ABOVE]) { actionAbove = 1; } } switch(event->data.l[0]) { case 0: /* Remove */ if(actionStick) { SetClientSticky(np, 0); } if(maxFlags != MAX_NONE && np->state.maxFlags) { MaximizeClient(np, np->state.maxFlags & ~maxFlags); } if(actionShade) { UnshadeClient(np); } if(actionFullScreen) { SetClientFullScreen(np, 0); } if(actionMinimize) { RestoreClient(np, 0); } if(actionNolist) { np->state.status &= ~STAT_NOLIST; RequireTaskUpdate(); } if(actionNopager) { np->state.status &= ~STAT_NOPAGER; RequirePagerUpdate(); } if(actionBelow && np->state.layer == LAYER_BELOW) { SetClientLayer(np, np->state.defaultLayer); } if(actionAbove && np->state.layer == LAYER_ABOVE) { SetClientLayer(np, np->state.defaultLayer); } break; case 1: /* Add */ if(actionStick) { SetClientSticky(np, 1); } if(maxFlags != MAX_NONE) { MaximizeClient(np, np->state.maxFlags | maxFlags); } if(actionShade) { ShadeClient(np); } if(actionFullScreen) { SetClientFullScreen(np, 1); } if(actionMinimize) { MinimizeClient(np, 1); } if(actionNolist) { np->state.status |= STAT_NOLIST; RequireTaskUpdate(); } if(actionNopager) { np->state.status |= STAT_NOPAGER; RequirePagerUpdate(); } if(actionBelow) { SetClientLayer(np, LAYER_BELOW); } if(actionAbove) { SetClientLayer(np, LAYER_ABOVE); } break; case 2: /* Toggle */ if(actionStick) { if(np->state.status & STAT_STICKY) { SetClientSticky(np, 0); } else { SetClientSticky(np, 1); } } if(maxFlags) { MaximizeClient(np, np->state.maxFlags ^ maxFlags); } if(actionShade) { if(np->state.status & STAT_SHADED) { UnshadeClient(np); } else { ShadeClient(np); } } if(actionFullScreen) { if(np->state.status & STAT_FULLSCREEN) { SetClientFullScreen(np, 0); } else { SetClientFullScreen(np, 1); } } if(actionBelow) { if(np->state.layer == LAYER_BELOW) { SetClientLayer(np, np->state.defaultLayer); } else { SetClientLayer(np, LAYER_BELOW); } } if(actionAbove) { if(np->state.layer == LAYER_ABOVE) { SetClientLayer(np, np->state.defaultLayer); } else { SetClientLayer(np, LAYER_ABOVE); } } /* Note that we don't handle toggling of hidden per EWMH * recommendations. */ if(actionNolist) { np->state.status ^= STAT_NOLIST; RequireTaskUpdate(); } if(actionNopager) { np->state.status ^= STAT_NOPAGER; RequirePagerUpdate(); } break; default: Debug("bad _NET_WM_STATE action: %ld", event->data.l[0]); break; } /* Update _NET_WM_STATE if needed. * The state update is handled elsewhere for the other actions. */ if(actionNolist | actionNopager | actionAbove | actionBelow) { WriteState(np); } }
/* ** A "local" function of ProcessRequest() . Stores #data# in #directory# with ** the attributes indicated by #s#. Fails if the record size and count in #s# ** yield more than #max_size# total bytes. Returns 1 if successful, else 0. */ static int KeepState(const struct loglocation* logLoc, const struct state *s, const char *data, size_t max_size) { const char *curr; int i; size_t recordSize; if(s->rec_count > fileSize) { FAIL("KeepState: rec count too big\n"); } if(s->rec_size > MAX_RECORD_SIZE) { WARN("KeepState: state record too big.\n"); recordSize = MAX_RECORD_SIZE; } else { recordSize = (size_t)s->rec_size; } if(s->rec_count * recordSize > max_size) { FAIL1("KeepState: too much data %d\n", s->rec_count * recordSize); } #ifdef WITH_NETLOGGER if (logLoc->loc_type==MEMORY_LOG_NETLOGGER) { for(curr = data, i = 0; i < s->rec_count; curr += recordSize, i++) { if(!WriteStateNL(logLoc->path, s->id, fileSize, s->time_out, s->seq_no, curr, recordSize) || !EnterInJournal(s->id, s->seq_no)) { if(errno == EMFILE) { CheckConnections(); } FAIL("KeepState: write failed\n"); } } return (1); } #endif /* WITH_NETLOGGER */ for(curr = data, i = 0; i < s->rec_count; curr += recordSize, i++) { if(!WriteState(FileOfState(logLoc->path, s->id), fileSize, s->time_out, s->seq_no, curr, recordSize) || !EnterInJournal(s->id, s->seq_no)) { if(errno == EMFILE) { CheckConnections(); } FAIL("KeepState: write failed\n"); } } return(1); }
COptionsDlg::~COptionsDlg() { WriteState(); }
/** Set a client's full screen state. */ void SetClientFullScreen(ClientNode *np, char fullScreen) { XEvent event; int north, south, east, west; BoundingBox box; const ScreenType *sp; Assert(np); /* Make sure there's something to do. */ if(!fullScreen == !(np->state.status & STAT_FULLSCREEN)) { return; } if(!(np->state.border & BORDER_FULLSCREEN)) { return; } if(np->state.status & STAT_SHADED) { UnshadeClient(np); } if(fullScreen) { np->state.status |= STAT_FULLSCREEN; if(!(np->state.maxFlags)) { np->oldx = np->x; np->oldy = np->y; np->oldWidth = np->width; np->oldHeight = np->height; } sp = GetCurrentScreen(np->x, np->y); GetScreenBounds(sp, &box); GetBorderSize(&np->state, &north, &south, &east, &west); box.x += west; box.y += north; box.width -= east + west; box.height -= north + south; np->x = box.x; np->y = box.y; np->width = box.width; np->height = box.height; ResetBorder(np); } else { np->state.status &= ~STAT_FULLSCREEN; np->x = np->oldx; np->y = np->oldy; np->width = np->oldWidth; np->height = np->oldHeight; ConstrainSize(np); ConstrainPosition(np); if(np->state.maxFlags != MAX_NONE) { PlaceMaximizedClient(np, np->state.maxFlags); } ResetBorder(np); event.type = MapRequest; event.xmaprequest.send_event = True; event.xmaprequest.display = display; event.xmaprequest.parent = np->parent; event.xmaprequest.window = np->window; JXSendEvent(display, rootWindow, False, SubstructureRedirectMask, &event); } WriteState(np); SendConfigureEvent(np); RequireRestack(); }
/** Resize a client window (mouse initiated). */ void ResizeClient(ClientNode *np, BorderActionType action, int startx, int starty) { XEvent event; int oldx, oldy; int oldw, oldh; int gwidth, gheight; int lastgwidth, lastgheight; int delta; int north, south, east, west; int ratio, minr, maxr; Assert(np); if(!(np->state.border & BORDER_RESIZE)) { return; } if(JUNLIKELY(!GrabMouseForResize(action))) { Debug("ResizeClient: could not grab mouse"); return; } if(np->state.status & STAT_SHADED) { action &= ~(BA_RESIZE_N | BA_RESIZE_S); } np->controller = ResizeController; shouldStopResize = 0; oldx = np->x; oldy = np->y; oldw = np->width; oldh = np->height; gwidth = (np->width - np->baseWidth) / np->xinc; gheight = (np->height - np->baseHeight) / np->yinc; GetBorderSize(np, &north, &south, &east, &west); startx += np->x - west; starty += np->y - north; CreateResizeWindow(np); UpdateResizeWindow(np, gwidth, gheight); if(!(GetMouseMask() & (Button1Mask | Button3Mask))) { StopResize(np); return; } for(;;) { WaitForEvent(&event); if(shouldStopResize) { np->controller = NULL; return; } switch(event.type) { case ButtonRelease: if( event.xbutton.button == Button1 || event.xbutton.button == Button3) { StopResize(np); return; } break; case MotionNotify: SetMousePosition(event.xmotion.x_root, event.xmotion.y_root); DiscardMotionEvents(&event, np->window); if(action & BA_RESIZE_N) { delta = (event.xmotion.y - starty) / np->yinc; delta *= np->yinc; if(oldh - delta >= np->minHeight && (oldh - delta <= np->maxHeight || delta > 0)) { np->height = oldh - delta; np->y = oldy + delta; } if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { FixWidth(np); } } if(action & BA_RESIZE_S) { delta = (event.xmotion.y - starty) / np->yinc; delta *= np->yinc; np->height = oldh + delta; np->height = Max(np->height, np->minHeight); np->height = Min(np->height, np->maxHeight); if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { FixWidth(np); } } if(action & BA_RESIZE_E) { delta = (event.xmotion.x - startx) / np->xinc; delta *= np->xinc; np->width = oldw + delta; np->width = Max(np->width, np->minWidth); np->width = Min(np->width, np->maxWidth); if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { FixHeight(np); } } if(action & BA_RESIZE_W) { delta = (event.xmotion.x - startx) / np->xinc; delta *= np->xinc; if(oldw - delta >= np->minWidth && (oldw - delta <= np->maxWidth || delta > 0)) { np->width = oldw - delta; np->x = oldx + delta; } if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { FixHeight(np); } } if(np->sizeFlags & PAspect) { if((action & (BA_RESIZE_N | BA_RESIZE_S)) && (action & (BA_RESIZE_E | BA_RESIZE_W))) { /* Fixed point with a 16-bit fraction. */ ratio = (np->width << 16) / np->height; minr = (np->aspect.minx << 16) / np->aspect.miny; if(ratio < minr) { delta = np->width; np->width = (np->height * minr) >> 16; if(action & BA_RESIZE_W) { np->x -= np->width - delta; } } maxr = (np->aspect.maxx << 16) / np->aspect.maxy; if(ratio > maxr) { delta = np->height; np->height = (np->width << 16) / maxr; if(action & BA_RESIZE_N) { np->y -= np->height - delta; } } } } lastgwidth = gwidth; lastgheight = gheight; gwidth = (np->width - np->baseWidth) / np->xinc; gheight = (np->height - np->baseHeight) / np->yinc; if(lastgheight != gheight || lastgwidth != gwidth) { if(np->state.status & (STAT_HMAX | STAT_VMAX)) { np->state.status &= ~(STAT_HMAX | STAT_VMAX); WriteState(np); SendConfigureEvent(np); } UpdateResizeWindow(np, gwidth, gheight); if(resizeMode == RESIZE_OUTLINE) { ClearOutline(); if(np->state.status & STAT_SHADED) { DrawOutline(np->x - west, np->y - north, np->width + west + east, north + south); } else { DrawOutline(np->x - west, np->y - north, np->width + west + east, np->height + north + south); } } else { ResetRoundedRectWindow(np->parent); if(np->state.status & STAT_SHADED) { ShapeRoundedRectWindow(np->parent, np->width + east + west, north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + west + east, north + south); } else { ShapeRoundedRectWindow(np->parent, np->width + east + west, np->height + north + south); JXMoveResizeWindow(display, np->parent, np->x - west, np->y - north, np->width + west + east, np->height + north + south); } JXMoveResizeWindow(display, np->window, west, north, np->width, np->height); SendConfigureEvent(np); } UpdatePager(); } break; default: break; }