Fixes an issue in which the local and the remote videos in a call could disappear from the display.

cusax-fix
Lyubomir Marinov 13 years ago
parent 02b5ab7f02
commit f5d8e03d62

@ -175,6 +175,13 @@ public class CallPanel
*/
private DialpadDialog dialpadDialog;
/**
* The indicator which determines whether {@link #dispose()} has already
* been invoked on this instance. If <tt>true</tt>, this instance is
* considered non-functional and is to be left to the garbage collector.
*/
private boolean disposed = false;
/**
* The handler for DTMF tones.
*/
@ -295,7 +302,17 @@ public void update(Observable o, Object arg)
{
public void run()
{
updateViewFromModelInEventDispatchThread();
/*
* We receive events/notifications from various threads and we
* respond to them in the AWT event dispatching thread. It is
* possible to first schedule an event to be brought to the AWT
* event dispatching thread, then to have #dispose() invoked on
* this instance and, finally, to receive the scheduled event in
* the AWT event dispatching thread. In such a case, this
* disposed instance should not respond to the event.
*/
if (!disposed)
updateViewFromModelInEventDispatchThread();
}
};
@ -585,6 +602,8 @@ private JComponent createBottomBar()
*/
void dispose()
{
disposed = true;
callConference.removeCallChangeListener(callConferenceListener);
callConference.removeCallPeerConferenceListener(callConferenceListener);
callConference.removePropertyChangeListener(callConferenceListener);
@ -1940,12 +1959,23 @@ private void updateSettingsPanelInEventDispatchThread(
*/
private void updateViewFromModel()
{
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event.
*/
if (!disposed)
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
}
}
}
@ -1956,6 +1986,17 @@ private void updateViewFromModel()
*/
private void updateViewFromModelInEventDispatchThread()
{
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event.
*/
if (disposed)
return;
/*
* We may add, remove, show, and hide various Components of the user
* interface hierarchy of this instance bellow. Consequently, this view

@ -18,7 +18,6 @@
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import org.jitsi.service.audionotifier.*;
import org.jitsi.service.protocol.*;
/**

@ -44,6 +44,13 @@ public class OneToOneCallPeerPanel
implements CallPeerRenderer,
Skinnable
{
/**
* The <tt>Logger</tt> used by the <tt>OneToOneCallPeerPanel</tt> class and
* its instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(OneToOneCallPeerPanel.class);
/**
* Serial version UID.
*/
@ -82,6 +89,13 @@ public class OneToOneCallPeerPanel
*/
private Component closeLocalVisualComponentButton;
/**
* The indicator which determines whether {@link #dispose()} has already
* been invoked on this instance. If <tt>true</tt>, this instance is
* considered non-functional and is to be left to the garbage collector.
*/
private boolean disposed = false;
/**
* The DTMF label.
*/
@ -203,7 +217,17 @@ public void update(Observable o, Object arg)
{
public void run()
{
updateViewFromModelInEventDispatchThread();
/*
* We receive events/notifications from various threads and we
* respond to them in the AWT event dispatching thread. It is
* possible to first schedule an event to be brought to the AWT
* event dispatching thread, then to have #dispose() invoked on
* this instance and, finally, to receive the scheduled event in
* the AWT event dispatching thread. In such a case, this
* disposed instance should not respond to the event.
*/
if (!disposed)
updateViewFromModelInEventDispatchThread();
}
};
@ -451,6 +475,7 @@ private VideoContainer createVideoContainer(Component noVideoComponent)
*/
public void dispose()
{
disposed = true;
callPeerAdapter.dispose();
uiVideoHandler.deleteObserver(uiVideoHandlerObserver);
}
@ -1173,12 +1198,26 @@ public void componentResized(ComponentEvent e)
*/
private void updateViewFromModel()
{
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event
* because it may, for example, steal a visual Components depicting
* video (which cannot belong to more than one parent at a time) from
* another non-disposed OneToOneCallPeerPanel.
*/
if (!disposed)
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
}
}
}
@ -1189,6 +1228,20 @@ private void updateViewFromModel()
*/
private void updateViewFromModelInEventDispatchThread()
{
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event
* because it may, for example, steal a visual Components depicting
* video (which cannot belong to more than one parent at a time) from
* another non-disposed OneToOneCallPeerPanel.
*/
if (disposed)
return;
/*
* Update the display of visual <tt>Component</tt>s depicting video
* streaming between the local peer/user and the remote peer(s).
@ -1238,6 +1291,9 @@ private void updateViewFromModelInEventDispatchThread()
* Well, we cannot do much about the exception. We'll just
* not display the local video.
*/
logger.warn(
"Failed to retrieve local video to be displayed.",
ofe);
}
}
@ -1279,13 +1335,19 @@ private void updateViewFromModelInEventDispatchThread()
else
{
center.removeAll();
this.localVideo = null;
this.remoteVideo = null;
if (remoteVideo != null)
{
center.add(remoteVideo, VideoLayout.CENTER_REMOTE, -1);
this.remoteVideo = remoteVideo;
this.remoteVideo = remoteVideo;
}
if (localVideo != null)
{
center.add(localVideo, VideoLayout.LOCAL, -1);
this.localVideo = localVideo;
if (closeLocalVisualComponentButton == null)
{
@ -1298,7 +1360,6 @@ private void updateViewFromModelInEventDispatchThread()
VideoLayout.CLOSE_LOCAL_BUTTON,
-1);
}
this.localVideo = localVideo;
}
}
}

@ -290,6 +290,7 @@ private static JComponent createVideoContainer(Component noVideoComponent)
private static class ComboRenderer
extends DefaultListCellRenderer
{
@Override
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus)
{

@ -175,7 +175,7 @@ public void loadSkin()
/**
* A custom menu item corresponding to a specific <tt>CallPeer</tt>.
*/
private class CallPeerMenuItem
private static class CallPeerMenuItem
extends JMenuItem
implements Skinnable
{
@ -202,16 +202,6 @@ public CallPeerMenuItem(CallPeer peer)
loadSkin();
}
/**
* Get the <tt>CallPeer</tt> of this instance.
*
* @return <tt>CallPeer</tt>
*/
public CallPeer getCallPeer()
{
return callPeer;
}
/**
* Reloads icon.
*/
@ -222,6 +212,5 @@ public void loadSkin()
if (peerIcon != null)
this.setIcon(new ImageIcon(peerIcon));
}
}
}

@ -275,6 +275,7 @@ private JPanel createSasPanel()
TransparentPanel sasPanel = new TransparentPanel()
{
@Override
public void paintComponent(Graphics g)
{
g = g.create();
@ -428,7 +429,8 @@ private void initZidNameButton()
{
public void actionPerformed(ActionEvent e)
{
// Set ZID name only for verfied peers (SAS compared and confirmed)
// Set ZID name only for verified peers (SAS compared and
// confirmed).
if (!sasVerified)
return;
@ -505,10 +507,7 @@ public void securityOff(CallPeerSecurityOffEvent evt)
repaint();
}
public void securityTimeout(CallPeerSecurityTimeoutEvent evt)
{
}
public void securityTimeout(CallPeerSecurityTimeoutEvent ev) {}
/**
* Reloads icons and components.

@ -55,6 +55,13 @@ public abstract class BasicConferenceCallPanel
private final Map<CallPeer, ConferenceCallPeerRenderer> callPeerPanels
= new HashMap<CallPeer, ConferenceCallPeerRenderer>();
/**
* The indicator which determines whether {@link #dispose()} has already
* been invoked on this instance. If <tt>true</tt>, this instance is
* considered non-functional and is to be left to the garbage collector.
*/
private boolean disposed = false;
/**
* The <tt>Runnable</tt> which is scheduled by
* {@link #updateViewFromModel()} for execution in the AWT event dispatching
@ -66,7 +73,17 @@ public abstract class BasicConferenceCallPanel
{
public void run()
{
updateViewFromModelInEventDispatchThread();
/*
* We receive events/notifications from various threads and we
* respond to them in the AWT event dispatching thread. It is
* possible to first schedule an event to be brought to the AWT
* event dispatching thread, then to have #dispose() invoked on
* this instance and, finally, to receive the scheduled event in
* the AWT event dispatching thread. In such a case, this
* disposed instance should not respond to the event.
*/
if (!disposed)
updateViewFromModelInEventDispatchThread();
}
};
@ -182,6 +199,8 @@ protected void conferenceMemberRemoved(CallPeerConferenceEvent ev)
*/
public void dispose()
{
disposed = true;
callConference.removeCallChangeListener(callConferenceListener);
callConference.removeCallPeerConferenceListener(callConferenceListener);
@ -259,6 +278,18 @@ protected void initializeComplete()
updateViewFromModel();
}
/**
* Returns <tt>true</tt> if {@link #dispose()} has already been invoked on
* this instance; otherwise, <tt>false</tt>.
*
* @return <tt>true</tt> if <tt>dispose()</tt> has already been invoked on
* this instance; otherwise, <tt>false</tt>
*/
protected final boolean isDisposed()
{
return disposed;
}
/**
* Notifies this instance about a specific <tt>CallPeerConferenceEvent</tt>
* fired in the telephony conference depicted by this instance.
@ -315,12 +346,23 @@ protected void onCallPeerEvent(CallPeerEvent ev)
*/
protected void updateViewFromModel()
{
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event.
*/
if (!disposed)
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
if (SwingUtilities.isEventDispatchThread())
updateViewFromModelInEventDispatchThread();
else
{
SwingUtilities.invokeLater(
updateViewFromModelInEventDispatchThread);
}
}
}
@ -401,6 +443,17 @@ protected abstract ConferenceCallPeerRenderer updateViewFromModel(
*/
protected void updateViewFromModelInEventDispatchThread()
{
/*
* We receive events/notifications from various threads and we respond
* to them in the AWT event dispatching thread. It is possible to first
* schedule an event to be brought to the AWT event dispatching thread,
* then to have #dispose() invoked on this instance and, finally, to
* receive the scheduled event in the AWT event dispatching thread. In
* such a case, this disposed instance should not respond to the event.
*/
if (disposed)
return;
/* Update the view of the local peer/user. */
updateViewFromModel(null);

@ -13,8 +13,6 @@
import javax.swing.*;
import com.sun.org.apache.bcel.internal.generic.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.call.*;
import net.java.sip.communicator.impl.gui.main.contactlist.contactsource.*;
@ -24,7 +22,6 @@
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
// disambiguation
/**
* The invite dialog is the one shown when the user clicks on the conference

Loading…
Cancel
Save