001/* [{ 002Copyright 2009 Nicolas Carranza <nicarran at gmail.com> 003 004This file is part of jpen. 005 006jpen is free software: you can redistribute it and/or modify 007it under the terms of the GNU Lesser General Public License as published by 008the Free Software Foundation, either version 3 of the License, 009or (at your option) any later version. 010 011jpen is distributed in the hope that it will be useful, 012but WITHOUT ANY WARRANTY; without even the implied warranty of 013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014GNU Lesser General Public License for more details. 015 016You should have received a copy of the GNU Lesser General Public License 017along with jpen. If not, see <http://www.gnu.org/licenses/>. 018}] */ 019package jpen.internal; 020 021import java.awt.KeyboardFocusManager; 022import java.awt.Window; 023import java.beans.PropertyChangeEvent; 024import java.beans.PropertyChangeListener; 025import java.util.concurrent.Executors; 026import java.util.concurrent.ScheduledExecutorService; 027import java.util.concurrent.ScheduledFuture; 028import java.util.concurrent.ThreadFactory; 029import java.util.concurrent.TimeUnit; 030import javax.swing.SwingUtilities; 031/** 032Allows to keep an eye on the application active window avoiding the unnecessary null activeWindow change reported by the default KeyboardFocusManager when switching windows. 033*/ 034public final class ActiveWindowProperty 035 implements PropertyChangeListener, Runnable{ 036 037 public interface Listener{ 038 void activeWindowChanged(Window newWindow); 039 } 040 041 private final Listener listener; 042 private Window activeWindow; 043 044 public ActiveWindowProperty(Listener listener){ 045 this.listener=listener; 046 KeyboardFocusManager keyboardFocusManager=KeyboardFocusManager.getCurrentKeyboardFocusManager(); 047 keyboardFocusManager.addPropertyChangeListener("activeWindow",this); 048 activeWindow=keyboardFocusManager.getActiveWindow(); 049 } 050 051 public synchronized Window get(){ 052 return activeWindow; 053 } 054 055 private synchronized void set(Window activeWindow){ 056 this.activeWindow=activeWindow; 057 listener.activeWindowChanged(activeWindow); 058 } 059 060 //@Override 061 public void propertyChange(PropertyChangeEvent ev){ 062 Window activeWindow=(Window)ev.getNewValue(); 063 if(activeWindow==this.activeWindow) 064 return; 065 if(activeWindow==null){ 066 // if the new activeWindow is null then we do the change only after a delay to avoid unnecessary changes to null (java does change the activeWindow to null when switching). 067 if(nullWindowTask==null || nullWindowTask.isDone()) 068 nullWindowTask=nullWindowScheduler.schedule(this, 50, TimeUnit.MILLISECONDS); 069 return; 070 } 071 if(nullWindowTask!=null){ 072 nullWindowTask.cancel(false); 073 nullWindowTask=null; 074 } 075 set(activeWindow); 076 } 077 078 private final ScheduledExecutorService nullWindowScheduler=Executors.newSingleThreadScheduledExecutor(new ThreadFactory(){ 079 //@Override 080 public Thread newThread(Runnable runnable){ 081 Thread t=new Thread(runnable, "jpen-ActiveWindow-filter"); 082 t.setDaemon(true); 083 return t; 084 } 085 }); 086 private ScheduledFuture nullWindowTask; 087 088 //@Override 089 public void run(){ 090 try{ 091 SwingUtilities.invokeAndWait(nullWindowRunnable); 092 }catch(Exception ex){ 093 throw new AssertionError(ex); 094 } 095 } 096 097 private final Runnable nullWindowRunnable=new Runnable(){ 098 //@Override 099 public void run(){ 100 set(null); 101 } 102 }; 103}