diff options
Diffstat (limited to 'src')
12 files changed, 1277 insertions, 234 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java index 47500e5..2c13dc5 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/CallManager.java @@ -8,7 +8,6 @@ package net.java.sip.communicator.impl.gui.main.call; import java.text.*; import java.util.*; -import java.util.List; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.customcontrols.*; @@ -16,10 +15,12 @@ import net.java.sip.communicator.impl.gui.main.*; import net.java.sip.communicator.impl.gui.main.contactlist.*; import net.java.sip.communicator.impl.gui.utils.*; import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.neomedia.device.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.transparent.*; /** * The <tt>CallManager</tt> is the one that handles calls. It contains also @@ -315,8 +316,56 @@ public class CallManager ProtocolProviderService protocolProvider, String contact) { - // Use the default media device corresponding to the screen to share - createDesktopSharing(protocolProvider, contact, null); + // If the user presses cancel on the desktop sharing warning then we + // have nothing more to do here. + if (!showDesktopSharingWarning()) + return; + + MediaService mediaService = GuiActivator.getMediaService(); + + List<MediaDevice> desktopDevices = mediaService.getDevices( + MediaType.VIDEO, MediaUseCase.DESKTOP); + + int deviceNumber = desktopDevices.size(); + + if (deviceNumber == 1) + { + createDesktopSharing( + protocolProvider, contact, desktopDevices.get(0)); + } + else if (deviceNumber > 1) + { + SelectScreenDialog selectDialog + = new SelectScreenDialog(desktopDevices); + + selectDialog.setVisible(true); + + createDesktopSharing( protocolProvider, + contact, + selectDialog.getSelectedDevice()); + } + } + + /** + * Creates a region desktop sharing through the given + * <tt>protocolProvider</tt> with the given <tt>contact</tt>. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>, through + * which the sharing session will be established + * @param contact the address of the contact recipient + */ + public static void createRegionDesktopSharing( + ProtocolProviderService protocolProvider, + String contact) + { + if (showDesktopSharingWarning()) + { + TransparentFrame frame = DesktopSharingFrame.createTransparentFrame( + protocolProvider, contact, true); + + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } } /** @@ -325,22 +374,64 @@ public class CallManager * * @param protocolProvider the protocol provider to which this call belongs. * @param contact the contact to call to - * @param mediaDevice the media device corresponding to the screen to share + * @param x the x coordinate of the shared region + * @param y the y coordinated of the shared region + * @param width the width of the shared region + * @param height the height of the shared region */ - public static void createDesktopSharing( + public static void createRegionDesktopSharing( ProtocolProviderService protocolProvider, String contact, - MediaDevice mediaDevice) + int x, + int y, + int width, + int height) { - if (showDesktopSharingWarning()) + MediaService mediaService = GuiActivator.getMediaService(); + + List<MediaDevice> desktopDevices = mediaService.getDevices( + MediaType.VIDEO, MediaUseCase.DESKTOP); + + int deviceNumber = desktopDevices.size(); + + if (deviceNumber == 1) + { + createDesktopSharing(protocolProvider, contact, + mediaService.getMediaDeviceForPartialDesktopStreaming( + desktopDevices.get(0), width, height, x, y)); + } + else if (deviceNumber > 1) { - new CreateDesktopSharingThread( protocolProvider, - contact, - mediaDevice).start(); + SelectScreenDialog selectDialog + = new SelectScreenDialog(desktopDevices); + + selectDialog.setVisible(true); + + createDesktopSharing(protocolProvider, contact, + mediaService.getMediaDeviceForPartialDesktopStreaming( + selectDialog.getSelectedDevice(), width, height, x, y)); } } /** + * Creates a desktop sharing call to the contact represented by the given + * string. + * + * @param protocolProvider the protocol provider to which this call belongs. + * @param contact the contact to call to + * @param mediaDevice the media device corresponding to the screen to share + */ + private static void createDesktopSharing( + ProtocolProviderService protocolProvider, + String contact, + MediaDevice mediaDevice) + { + new CreateDesktopSharingThread( protocolProvider, + contact, + mediaDevice).start(); + } + + /** * Enables the desktop sharing in an existing <tt>call</tt>. * * @param call the call for which desktop sharing should be enabled @@ -349,7 +440,102 @@ public class CallManager */ public static void enableDesktopSharing(Call call, boolean enable) { - enableDesktopSharing(call, null, enable); + if (!enable) + enableDesktopSharing(call, null, enable); + else if (showDesktopSharingWarning()) + { + MediaService mediaService = GuiActivator.getMediaService(); + + List<MediaDevice> desktopDevices = mediaService.getDevices( + MediaType.VIDEO, MediaUseCase.DESKTOP); + + int deviceNumber = desktopDevices.size(); + + if (deviceNumber == 1) + { + enableDesktopSharing(call, null, enable); + } + else if (deviceNumber > 1) + { + SelectScreenDialog selectDialog + = new SelectScreenDialog(desktopDevices); + + selectDialog.setVisible(true); + + enableDesktopSharing( + call, selectDialog.getSelectedDevice(), enable); + } + } + + // in case we switch to video, disable remote control if it was + // enabled + enableDesktopRemoteControl(call.getCallPeers().next(), false); + } + + /** + * Enables the region desktop sharing for the given call. + * + * @param call the call, for which the region desktop sharing should be + * enabled + * @param enable indicates if the desktop sharing should be enabled or + * disabled + */ + public static void enableRegionDesktopSharing(Call call, boolean enable) + { + if (!enable) + enableDesktopSharing(call, null, enable); + else if (showDesktopSharingWarning()) + { + TransparentFrame frame + = DesktopSharingFrame.createTransparentFrame(call, true); + + frame.setVisible(true); + } + } + + /** + * Creates a desktop sharing call to the contact represented by the given + * string. + * + * @param call the call for which desktop sharing should be enabled + * @param x the x coordinate of the shared region + * @param y the y coordinated of the shared region + * @param width the width of the shared region + * @param height the height of the shared region + */ + public static void enableRegionDesktopSharing( + Call call, + int x, + int y, + int width, + int height) + { + // Use the default media device corresponding to the screen to share + MediaService mediaService = GuiActivator.getMediaService(); + + List<MediaDevice> desktopDevices = mediaService.getDevices( + MediaType.VIDEO, MediaUseCase.DESKTOP); + + int deviceNumber = desktopDevices.size(); + + if (deviceNumber == 1) + { + enableDesktopSharing(call, + mediaService.getMediaDeviceForPartialDesktopStreaming( + desktopDevices.get(0), width, height, x, y), true); + } + else if (deviceNumber > 1) + { + SelectScreenDialog selectDialog + = new SelectScreenDialog(desktopDevices); + + selectDialog.setVisible(true); + + enableDesktopSharing(call, + mediaService.getMediaDeviceForPartialDesktopStreaming( + selectDialog.getSelectedDevice(), width, height, x, y), + true); + } // in case we switch to video, disable remote control if it was // enabled @@ -364,7 +550,7 @@ public class CallManager * @param enable indicates if the desktop sharing should be enabled or * disabled */ - public static void enableDesktopSharing(Call call, + private static void enableDesktopSharing(Call call, MediaDevice mediaDevice, boolean enable) { @@ -383,27 +569,24 @@ public class CallManager if (enable && isLocalVideoEnabled(call)) enableLocalVideo(call, false); - if (!enable || showDesktopSharingWarning()) + try { - try - { - if (mediaDevice != null) - desktopOpSet.setLocalVideoAllowed( - call, - mediaDevice, - enable); - else - desktopOpSet.setLocalVideoAllowed( - call, - enable); - - enableSucceeded = true; - } - catch (OperationFailedException ex) - { - logger.error( - "Failed to toggle the streaming of local video.", ex); - } + if (mediaDevice != null) + desktopOpSet.setLocalVideoAllowed( + call, + mediaDevice, + enable); + else + desktopOpSet.setLocalVideoAllowed( + call, + enable); + + enableSucceeded = true; + } + catch (OperationFailedException ex) + { + logger.error( + "Failed to toggle the streaming of local video.", ex); } } @@ -434,6 +617,28 @@ public class CallManager } /** + * Indicates if the desktop sharing is currently enabled for the given + * <tt>call</tt>. + * + * @param call the <tt>Call</tt>, for which we would to check if the desktop + * sharing is currently enabled + * @return <tt>true</tt> if the desktop sharing is currently enabled for the + * given <tt>call</tt>, <tt>false</tt> otherwise + */ + public static boolean isRegionDesktopSharingEnabled(Call call) + { + OperationSetDesktopSharingServer desktopOpSet + = call.getProtocolProvider().getOperationSet( + OperationSetDesktopSharingServer.class); + + if (desktopOpSet != null + && desktopOpSet.isPartialStreaming(call)) + return true; + + return false; + } + + /** * Enables/disables remote control when in a desktop sharing session with * the given <tt>callPeer</tt>. * diff --git a/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingButton.java b/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingButton.java index 00dc29d..8814f96 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingButton.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingButton.java @@ -6,12 +6,13 @@ */ package net.java.sip.communicator.impl.gui.main.call; -import java.util.*; +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.utils.*; -import net.java.sip.communicator.service.neomedia.*; -import net.java.sip.communicator.service.neomedia.device.*; import net.java.sip.communicator.service.protocol.*; /** @@ -70,23 +71,67 @@ public class DesktopSharingButton // Otherwise we enable the desktop sharing. else { - MediaService mediaService = GuiActivator.getMediaService(); + //We'll select the button once the desktop sharing has been + // established. + setSelected(false); - List<MediaDevice> desktopDevices = mediaService.getDevices( - MediaType.VIDEO, MediaUseCase.DESKTOP); + JPopupMenu sharingMenu = createDesktopSharingMenu(); - int deviceNumber = desktopDevices.size(); + Point location = new Point(getX(), getY() + getHeight()); - if (deviceNumber == 1) - CallManager.enableDesktopSharing(call, true); - else if (deviceNumber > 1) - { - SelectScreenDialog selectDialog - = new SelectScreenDialog(call, desktopDevices); + SwingUtilities.convertPointToScreen(location, getParent()); - selectDialog.setVisible(true); - } + sharingMenu.setLocation(location); + sharingMenu.setVisible(true); } } } + + /** + * Creates the menu responsible for desktop sharing when a single desktop + * sharing contact is available. + * + * @return the created popup menu + */ + private JPopupMenu createDesktopSharingMenu() + { + final JPopupMenu popupMenu = new JPopupMenu( + GuiActivator.getResources().getI18NString( + "service.gui.SHARE_DESKTOP")); + + popupMenu.setInvoker(this); + popupMenu.setFocusable(true); + + JMenuItem shareFullScreen = new JMenuItem(GuiActivator.getResources() + .getI18NString("service.gui.SHARE_FULL_SCREEN")); + + JMenuItem shareRegion = new JMenuItem(GuiActivator.getResources() + .getI18NString("service.gui.SHARE_REGION")); + + shareRegion.setEnabled(false); + + popupMenu.add(shareFullScreen); + popupMenu.add(shareRegion); + + shareFullScreen.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + popupMenu.setVisible(false); + CallManager.enableDesktopSharing(call, true); + } + }); + + shareRegion.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + popupMenu.setVisible(false); + + CallManager.enableRegionDesktopSharing(call, true); + } + }); + + return popupMenu; + } }
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingFrame.java b/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingFrame.java new file mode 100644 index 0000000..19b3788 --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/call/DesktopSharingFrame.java @@ -0,0 +1,567 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.impl.gui.main.call; + +import java.awt.*; +import java.awt.event.*; +import java.awt.geom.*; +import java.beans.*; +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.service.neomedia.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; +import net.java.sip.communicator.util.swing.transparent.*; + +/** + * + * @author Yana Stamcheva + */ +public class DesktopSharingFrame +{ + /** + * Used for logging. + */ + private static final Logger logger + = Logger.getLogger(DesktopSharingFrame.class); + + /** + * The icon shown to indicate the resize drag area. + */ + private static final ImageIcon resizeIcon + = GuiActivator.getResources().getImage( + "service.gui.icons.WINDOW_RESIZE_ICON"); + + /** + * The indent of the sharing region from the frame. + */ + private static int SHARING_REGION_INDENT = 2; + + /** + * The x coordinate of the frame, which started the regional sharing. + */ + private static int initialFrameX = -1; + + /** + * The y coordinate of the frame, which started the regional sharing. + */ + private static int initialFrameY = -1; + + /** + * The width of the sharing region, which started the sharing. + */ + private static int sharingRegionWidth = -1; + + /** + * The height of the sharing region, which started the sharing. + */ + private static int sharingRegionHeight = -1; + + /** + * A mapping of a desktop sharing frame created by this class and a call. + */ + private static final Map<Call, JFrame> callDesktopFrames + = new Hashtable<Call, JFrame>(); + + /** + * Creates the transparent desktop sharing frame. + * + * @param protocolProvider the protocol provider, through which the desktop + * sharing will pass + * @param contactAddress the address of the contact to call + * @param initialFrame indicates if this is the frame which initiates the + * desktop sharing + * @return the created desktop sharing frame + */ + public static TransparentFrame createTransparentFrame( + ProtocolProviderService protocolProvider, + String contactAddress, + boolean initialFrame) + { + TransparentFrame frame = TransparentFrame.createTransparentFrame(); + + initContentPane(frame, initialFrame); + + JComponent sharingRegion = new TransparentPanel(); + // The preferred width on MacOSX should be a multiple of 16, that's why + // we put 592 as a default width. + sharingRegion.setPreferredSize(new Dimension(592, 400)); + + frame.getContentPane().add(sharingRegion, BorderLayout.NORTH); + + JPanel buttonPanel = initButtons( + frame, sharingRegion, initialFrame, null, + protocolProvider, contactAddress); + + frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + frame.pack(); + + return frame; + } + + /** + * Creates the transparent desktop sharing frame. + * + * @param call the current call + * @param initialFrame indicates if this is the frame which initiates the + * desktop sharing + * @return the created desktop sharing frame + */ + public static TransparentFrame createTransparentFrame( + Call call, + boolean initialFrame) + { + TransparentFrame frame = TransparentFrame.createTransparentFrame(); + + initContentPane(frame, initialFrame); + + JComponent sharingRegion = new TransparentPanel(); + // The preferred width on MacOSX should be a multiple of 16, + // that's why we put 592 as a default width. + sharingRegion.setPreferredSize(new Dimension(592, 400)); + frame.getContentPane().add(sharingRegion, BorderLayout.NORTH); + + JPanel buttonPanel = initButtons( + frame, sharingRegion, initialFrame, call, null, null); + + frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH); + + // If the desktop sharing has started we store the frame to call mapping. + if (!initialFrame) + { + callDesktopFrames.put(call, frame); + addCallListener(call, frame); + addFrameListener(call, frame, sharingRegion); + addDesktopSharingListener(call, frame); + + logger.info("The sharing region width: " + sharingRegionWidth); + + if (sharingRegionWidth > -1 && sharingRegionHeight > -1) + sharingRegion.setPreferredSize( + new Dimension(sharingRegionWidth, sharingRegionHeight)); + + frame.pack(); + + if (initialFrameX > -1 && initialFrameY > -1) + frame.setLocation(initialFrameX, initialFrameY); + else + // By default we position the frame in the center of the screen. + // It's important to call this method after the pack(), because + // it requires the frame size to calculate the location. + frame.setLocationRelativeTo(null); + } + else + { + frame.pack(); + + // By default we position the frame in the center of the screen. + // It's important to call this method after the pack(), because + // it requires the frame size to calculate the location. + frame.setLocationRelativeTo(null); + } + + return frame; + } + + /** + * Adds a call listener, which listens for call ended events and would + * close any related desktop sharing frames when a call is ended. + * + * @param call the call, for which we're registering a listener + * @param frame the frame to be closed on call ended + */ + private static void addCallListener(Call call, JFrame frame) + { + OperationSetBasicTelephony telOpSet = call.getProtocolProvider() + .getOperationSet(OperationSetBasicTelephony.class); + + if (telOpSet != null) // This should be always true. + { + telOpSet.addCallListener(new CallListener() + { + /** + * Implements CallListener.callEnded. Disposes the frame + * related to the ended call. + * + * @param event the <tt>CallEvent</tt> that notified us + */ + public void callEnded(CallEvent event) + { + Call call = event.getSourceCall(); + JFrame desktopFrame = callDesktopFrames.get(call); + + if (desktopFrame != null) + { + desktopFrame.dispose(); + callDesktopFrames.remove(call); + } + } + + public void incomingCallReceived(CallEvent event) {} + + public void outgoingCallCreated(CallEvent event) {} + }); + } + } + + /** + * Adds the desktop sharing listener. + * + * @param call the call, for which we're registering a listener + * @param frame the frame to be closed on call ended + */ + private static void addDesktopSharingListener(final Call call, JFrame frame) + { + OperationSetVideoTelephony videoOpSet = + call.getProtocolProvider() + .getOperationSet(OperationSetVideoTelephony.class); + + videoOpSet.addPropertyChangeListener(call, new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent evt) + { + if (OperationSetVideoTelephony.LOCAL_VIDEO_STREAMING + .equals(evt.getPropertyName()) + && evt.getNewValue().equals(MediaDirection.RECVONLY)) + { + JFrame desktopFrame = callDesktopFrames.get(call); + + if (desktopFrame != null) + { + desktopFrame.dispose(); + callDesktopFrames.remove(call); + } + } + } + }); + } + + /** + * Initializes the content pane of the given window. + * + * @param frame the parent frame + * @param initialFrame indicates if this is the frame which initiates the + * desktop sharing + */ + private static void initContentPane(JFrame frame, boolean initialFrame) + { + JPanel contentPane = new JPanel() + { + protected void paintComponent(Graphics g) + { + if (TransparentFrame.isTranslucencySupported) + { + AntialiasingManager.activateAntialiasing(g); + final int R = 240; + final int G = 240; + final int B = 240; + + Paint p = + new GradientPaint(0.0f, 0.0f, new Color(R, G, B, 0), + getWidth(), getHeight(), new Color(R, G, B, 0), true); + Graphics2D g2d = (Graphics2D)g; + g2d.setPaint(p); + g2d.fillRect(0, 0, getWidth(), getHeight()); + g2d.setColor(new Color( Color.DARK_GRAY.getRed(), + Color.DARK_GRAY.getGreen(), + Color.DARK_GRAY.getBlue(), 180)); + g2d.setStroke( + new BasicStroke((float) 4)); + g2d.drawRoundRect( + 0, 0, getWidth() - 1, getHeight() - 1, 20, 20); + } + else + { + super.paintComponent(g); + } + } + }; + + contentPane.setOpaque(false); + contentPane.setDoubleBuffered(false); + contentPane.setLayout(new BorderLayout()); + contentPane.setBorder(BorderFactory.createEmptyBorder( + SHARING_REGION_INDENT, SHARING_REGION_INDENT, + SHARING_REGION_INDENT, SHARING_REGION_INDENT)); + + frame.setContentPane(contentPane); + + if (TransparentFrame.isTranslucencySupported) + frame.setAlwaysOnTop(true); + } + + /** + * Creates and initializes the button panel. + * + * @param frame the parent frame + * @param sharingRegion the sharing region component + * @param initialFrame indicates if this is the frame which initiates the + * desktop sharing + * @param call the current call, if we're in a call + * @param protocolProvider the protocol provider + * @param contact the contact, which is the receiver of the call + * + * @return the created button panel + */ + private static JPanel initButtons( + final JFrame frame, + final JComponent sharingRegion, + boolean initialFrame, + final Call call, + final ProtocolProviderService protocolProvider, + final String contact) + { + JPanel buttonPanel = new TransparentPanel(new GridBagLayout()) + { + public void paintComponent(Graphics g) + { + if (!TransparentFrame.isTranslucencySupported) + { + super.paintComponent(g); + return; + } + + Graphics2D g2d = (Graphics2D) g.create(); + + AntialiasingManager.activateAntialiasing(g2d); + + g2d.setColor(new Color( Color.DARK_GRAY.getRed(), + Color.DARK_GRAY.getGreen(), + Color.DARK_GRAY.getBlue(), 180)); + + GeneralPath shape = new GeneralPath(); + int x = -SHARING_REGION_INDENT + 2; + int y = 0; + int width = getWidth() + SHARING_REGION_INDENT*2 - 4; + int height = getHeight() + SHARING_REGION_INDENT*2 - 2; + + shape.moveTo(x, y); + shape.lineTo(width, y); + shape.lineTo(width, height - 12); + shape.curveTo(width, height - 12, + width, height, + width - 12, height); + shape.lineTo(12, height); + shape.curveTo(12, height, + x, height, + x, height - 12); + shape.lineTo(x, y); + shape.closePath(); + + g2d.fill(shape); + g2d.setColor(getBackground()); + } + }; + + GridBagConstraints constraints = new GridBagConstraints(); + + buttonPanel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + buttonPanel.setPreferredSize( + new Dimension(sharingRegion.getWidth(), 30)); + + if (initialFrame) + { + JButton startButton = createButton( + GuiActivator.getResources() + .getI18NString("service.gui.START_SHARING")); + + JButton cancelButton = createButton( + GuiActivator.getResources() + .getI18NString("service.gui.CANCEL")); + + constraints.gridx = 0; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.insets = new Insets(0, 0, 0, 5); + constraints.anchor = GridBagConstraints.EAST; + buttonPanel.add(cancelButton, constraints); + + constraints.gridx = 1; + constraints.gridy = 0; + constraints.weightx = 1.0; + constraints.anchor = GridBagConstraints.WEST; + buttonPanel.add(startButton, constraints); + + constraints.gridx = 3; + constraints.gridy = 0; + constraints.weightx = 0; + constraints.insets = new Insets(0, 0, 2, 2); + constraints.anchor = GridBagConstraints.SOUTHWEST; + buttonPanel.add( + createResizeLabel(frame, sharingRegion, buttonPanel), + constraints); + + startButton.setCursor(Cursor.getDefaultCursor()); + cancelButton.setCursor(Cursor.getDefaultCursor()); + + cancelButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent arg0) + { + frame.dispose(); + } + }); + + startButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + Point location = sharingRegion.getLocationOnScreen(); + + initialFrameX = frame.getX(); + initialFrameY = frame.getY(); + sharingRegionWidth = sharingRegion.getWidth(); + sharingRegionHeight = sharingRegion.getHeight(); + + frame.dispose(); + + if (call != null) + CallManager.enableRegionDesktopSharing( + call, location.x, location.y, + sharingRegionWidth, sharingRegionHeight); + else + CallManager.createRegionDesktopSharing( + protocolProvider, contact, + location.x, location.y, + sharingRegionWidth, sharingRegionHeight); + } + }); + } + else + { + JButton stopButton = createButton( + GuiActivator.getResources() + .getI18NString("service.gui.STOP_SHARING")); + + buttonPanel.add(stopButton); + + stopButton.setCursor(Cursor.getDefaultCursor()); + + stopButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + if (call != null) + CallManager.enableDesktopSharing(call, false); + + frame.dispose(); + } + }); + } + + return buttonPanel; + } + + /** + * Creates a button with the given text. + * + * @param text the text of the button + * @return the created button + */ + private static JButton createButton(String text) + { + JButton button = new JButton(text); + + button.setOpaque(false); + + return button; + } + + /** + * Creates the label allowing to resize the given frame. + * + * @param frame the frame to resize + * @param sharingRegion the sharing region + * @param buttonPanel the button panel, where the created label would be + * added + * @return the created resize label + */ + private static JLabel createResizeLabel(final JFrame frame, + final JComponent sharingRegion, + final JComponent buttonPanel) + { + final JLabel resizeLabel = new JLabel(resizeIcon); + resizeLabel.addMouseMotionListener(new MouseMotionAdapter() + { + public void mouseDragged(MouseEvent e) + { + Point p = e.getLocationOnScreen(); + Point regionLocation = sharingRegion.getLocationOnScreen(); + + int sharingWidth = (int) ( p.getX() + - regionLocation.getX() + - 2*SHARING_REGION_INDENT); + + int newSharingHeight = (int) (p.getY() + - frame.getY() + - buttonPanel.getHeight() + - 2*SHARING_REGION_INDENT); + + // We should make sure that the width on MacOSX is a multiple + // of 16. + if (OSUtils.IS_MAC && sharingWidth%16 > 0) + sharingWidth = sharingWidth - sharingWidth%16; + + sharingRegion.setPreferredSize( + new Dimension(sharingWidth, newSharingHeight)); + + frame.validate(); + + int height = (int) (p.getY() - frame.getY()); + + frame.setSize(sharingWidth + 2*SHARING_REGION_INDENT, height); + } + }); + + return resizeLabel; + } + + /** + * Adds a listener for the given frame and call + * + * @param call the underlying call + * @param frame the frame to which the listener would be added + * @param sharingRegion the sharing region + */ + private static void addFrameListener( final Call call, + final JFrame frame, + final Component sharingRegion) + { + frame.addComponentListener(new ComponentListener() + { + public void componentResized(ComponentEvent e) {} + + public void componentMoved(ComponentEvent e) + { + OperationSetDesktopSharingServer desktopOpSet + = call.getProtocolProvider().getOperationSet( + OperationSetDesktopSharingServer.class); + + if (desktopOpSet == null) + return; + + Point location = new Point( sharingRegion.getX(), + sharingRegion.getY()); + + SwingUtilities.convertPointToScreen(location, + frame.getContentPane()); + + desktopOpSet.movePartialDesktopStreaming( + call, location.x, location.y); + } + + public void componentShown(ComponentEvent e) {} + + public void componentHidden(ComponentEvent arg0) {} + }); + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java index a3e9b79..a5d58bc 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/OneToOneCallPeerPanel.java @@ -26,6 +26,7 @@ import net.java.sip.communicator.service.resources.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.skin.*; import net.java.sip.communicator.util.swing.*; +import net.java.sip.communicator.util.swing.transparent.*; /** * The <tt>OneToOneCallPeerPanel</tt> is the panel containing data for a call @@ -488,6 +489,15 @@ public class OneToOneCallPeerPanel if (CallManager.isDesktopSharingEnabled(call)) { callContainer.setDesktopSharingButtonSelected(true); + + if (CallManager.isRegionDesktopSharingEnabled(call)) + { + TransparentFrame frame + = DesktopSharingFrame.createTransparentFrame( + call, false); + + frame.setVisible(true); + } } else if (CallManager.isLocalVideoEnabled(call)) { @@ -1595,24 +1605,12 @@ public class OneToOneCallPeerPanel } } - /** - * {@inheritDoc} - */ public void mouseMoved(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mouseClicked(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mouseEntered(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mouseExited(MouseEvent event) {} /** @@ -1643,34 +1641,20 @@ public class OneToOneCallPeerPanel if (!closeButton.isVisible()) { Component c = (Component) event.getSource(); - closeButton.setLocation( - c.getX() + c.getWidth() - closeButton.getWidth() - 3, + closeButton.setLocation( + c.getX() + c.getWidth() - closeButton.getWidth() - 3, c.getY() + 3); closeButton.setVisible(true); } } } - /** - * The local video close button. - */ private class CloseButton extends Label implements MouseListener { - /** - * Serial version UID. - */ - private static final long serialVersionUID = 0L; - - /** - * Background image. - */ Image image = ImageLoader.getImage(ImageLoader.CLOSE_VIDEO); - /** - * Constructor. - */ public CloseButton() { int buttonWidth = image.getWidth(this) + 5; @@ -1682,9 +1666,6 @@ public class OneToOneCallPeerPanel this.addMouseListener(this); } - /** - * {@inheritDoc} - */ public void paint(Graphics g) { g.setColor(Color.GRAY); @@ -1694,9 +1675,6 @@ public class OneToOneCallPeerPanel getHeight()/2 - image.getHeight(this)/2, this); } - /** - * {@inheritDoc} - */ public void mouseClicked(MouseEvent event) { setLocalVideoVisible(false); @@ -1705,24 +1683,12 @@ public class OneToOneCallPeerPanel .setShowHideVideoButtonSelected(false); } - /** - * {@inheritDoc} - */ public void mouseEntered(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mouseExited(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mousePressed(MouseEvent event) {} - /** - * {@inheritDoc} - */ public void mouseReleased(MouseEvent event) {} } @@ -1781,19 +1747,6 @@ public class OneToOneCallPeerPanel .setShowHideVideoButtonSelected(isVisible); } - if(localVideo == null && isVisible) - { - /* create local visual component if not already created */ - try - { - videoTelephony.createLocalVisualComponent(callPeer, - null); - } - catch(OperationFailedException e) - { - } - } - int videoContainerCount; if ((videoTelephony != null) @@ -1804,12 +1757,28 @@ public class OneToOneCallPeerPanel if (localVideo != null) { - videoContainer.remove(localVideo); - videoContainer.remove(closeButton); - /* release resources */ - videoTelephony.disposeLocalVisualComponent(callPeer, - localVideo); - localVideo = null; + if (isVisible) + { + Container parent = localVideo.getParent(); + + if (parent != null) + { + parent.remove(parent); + parent.remove(closeButton); + } + + videoContainer.add( + closeButton, VideoLayout.CLOSE_LOCAL_BUTTON, 0); + videoContainer.add(localVideo, VideoLayout.LOCAL, 1); + } + else + { + if (localVideo != null) + { + videoContainer.remove(localVideo); + videoContainer.remove(closeButton); + } + } } } } diff --git a/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java b/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java index 3951e15..2f05509 100644 --- a/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java +++ b/src/net/java/sip/communicator/impl/gui/main/call/SelectScreenDialog.java @@ -17,7 +17,6 @@ import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.service.neomedia.*; import net.java.sip.communicator.service.neomedia.device.*; import net.java.sip.communicator.service.neomedia.format.*; -import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.util.*; import net.java.sip.communicator.util.swing.*; @@ -65,54 +64,9 @@ public class SelectScreenDialog private static MediaDevice videoDeviceInPreview; /** - * The parent call for which the screen is selected, if any. + * The selected media device. */ - private Call call; - - /** - * The protocol provider through which we make the sharing. - */ - private ProtocolProviderService protocolProvider; - - /** - * The contact with which we'd like to share our desktop. - */ - private String contact; - - /** - * Creates an instance of <tt>SelectScreenDialog</tt> by specifying the list - * of possible desktop devices to choose from. - * - * @param call the call, for which screen for desktop sharing is selected - * @param desktopDevices the list of possible desktop devices to choose - * from - */ - public SelectScreenDialog(Call call, List<MediaDevice> desktopDevices) - { - this(desktopDevices); - - this.call = call; - } - - /** - * Creates an instance of <tt>SelectScreenDialog</tt> by specifying the list - * of possible desktop devices to choose from. - * - * @param protocolProvider the protocol provider through which we make the - * sharing - * @param contact the contact to share the desktop with - * @param desktopDevices the list of possible desktop devices to choose - * from - */ - public SelectScreenDialog( ProtocolProviderService protocolProvider, - String contact, - List<MediaDevice> desktopDevices) - { - this(desktopDevices); - - this.protocolProvider = protocolProvider; - this.contact = contact; - } + private MediaDevice selectedDevice; /** * Creates an instance of <tt>SelectScreenDialog</tt> by specifying the list @@ -123,6 +77,8 @@ public class SelectScreenDialog */ public SelectScreenDialog(List<MediaDevice> desktopDevices) { + setModal(true); + setPreferredSize(new Dimension(400, 300)); Container contentPane = getContentPane(); @@ -139,6 +95,16 @@ public class SelectScreenDialog } /** + * Returns the selected device. + * + * @return the selected device + */ + public MediaDevice getSelectedDevice() + { + return selectedDevice; + } + + /** * Creates the buttons panel. * * @return the buttons panel @@ -155,17 +121,10 @@ public class SelectScreenDialog { public void actionPerformed(ActionEvent e) { - MediaDevice selectedDevice + selectedDevice = (MediaDevice) deviceComboBox.getSelectedItem(); dispose(); - - if (call != null) - CallManager.enableDesktopSharing(call, selectedDevice, true); - else - CallManager.createDesktopSharing( protocolProvider, - contact, - selectedDevice); } }); diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java index 7b3a311..05a8aec 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTreeCellRenderer.java @@ -1161,24 +1161,7 @@ public class ContactListTreeCellRenderer private void shareDesktop( ProtocolProviderService protocolProvider, String contactName) { - MediaService mediaService = GuiActivator.getMediaService(); - - List<MediaDevice> desktopDevices = mediaService.getDevices( - MediaType.VIDEO, MediaUseCase.DESKTOP); - - int deviceNumber = desktopDevices.size(); - - if (deviceNumber == 1) - CallManager.createDesktopSharing(protocolProvider, contactName); - else if (deviceNumber > 1) - { - SelectScreenDialog selectDialog - = new SelectScreenDialog( protocolProvider, - contactName, - desktopDevices); - - selectDialog.setVisible(true); - } + CallManager.createDesktopSharing(protocolProvider, contactName); } /** diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java index b0cf7c4..e8edc65 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/MetaContactRightButtonMenu.java @@ -122,18 +122,28 @@ public class MetaContactRightButtonMenu "service.gui.VIDEO_CALL")); /** - * The desktop sharing menu item. + * The menu responsible for desktop sharing when a single desktop sharing + * contact is available. */ - private final JMenuItem desktopSharingItem = new JMenuItem( + private final SIPCommMenu contactDesktopSharingMenu = new SIPCommMenu( GuiActivator.getResources().getI18NString( "service.gui.SHARE_DESKTOP")); /** - * The menu responsible for calling a contact with video. + * The menu responsible for full screen sharing when more than one contact + * is available for sharing. */ - private final SIPCommMenu desktopSharingMenu = new SIPCommMenu( + private final SIPCommMenu multiContactFullShareMenu = new SIPCommMenu( GuiActivator.getResources().getI18NString( - "service.gui.SHARE_DESKTOP")); + "service.gui.SHARE_FULL_SCREEN")); + + /** + * The menu responsible for region screen sharing when more than one contact + * is available for sharing. + */ + private final SIPCommMenu multiContactRegionShareMenu = new SIPCommMenu( + GuiActivator.getResources().getI18NString( + "service.gui.SHARE_REGION")); /** * The send message menu item. @@ -201,9 +211,14 @@ public class MetaContactRightButtonMenu private static final String videoCallPrefix = "videoCall:"; /** - * The prefix for video call contact menu. + * The prefix for full screen desktop sharing menu. */ - private static final String desktopSharingPrefix = "desktopSharing:"; + private static final String fullDesktopSharingPrefix = "shareFullScreen:"; + + /** + * The prefix for region screen desktop sharing menu. + */ + private static final String regionDesktopSharingPrefix = "shareRegionScreen:"; /** * The contact to move when the move menu has been chosen. @@ -367,9 +382,16 @@ public class MetaContactRightButtonMenu hasContactCapabilities(contact, OperationSetDesktopSharingServer.class)) { - desktopSharingMenu.add( + multiContactFullShareMenu.add( createMenuItem( contactDisplayName, - desktopSharingPrefix + fullDesktopSharingPrefix + + contact.getAddress() + + protocolProvider.getProtocolName(), + protocolIcon)); + + multiContactRegionShareMenu.add( + createMenuItem( contactDisplayName, + regionDesktopSharingPrefix + contact.getAddress() + protocolProvider.getProtocolName(), protocolIcon)); @@ -402,54 +424,69 @@ public class MetaContactRightButtonMenu this.videoCallItem.addActionListener(this); } - if (desktopSharingMenu.getItemCount() > 1) + if (multiContactFullShareMenu.getItemCount() > 1) { - this.add(desktopSharingMenu); + add(multiContactFullShareMenu); + add(multiContactRegionShareMenu); + + multiContactRegionShareMenu.setEnabled(false); } else { - this.add(desktopSharingItem); - this.desktopSharingItem.setName("desktopSharing"); - this.desktopSharingItem.addActionListener(this); + // Create desktop sharing menu. + contactDesktopSharingMenu.add( + createMenuItem( GuiActivator.getResources() + .getI18NString("service.gui.SHARE_FULL_SCREEN"), + "shareFullScreen", + null)); + + JMenuItem menuItem = createMenuItem( GuiActivator.getResources() + .getI18NString("service.gui.SHARE_REGION"), + "shareRegion", + null); + menuItem.setEnabled(false); + contactDesktopSharingMenu.add(menuItem); + + add(contactDesktopSharingMenu); } - this.add(sendFileItem); + add(sendFileItem); - this.addSeparator(); + addSeparator(); - this.add(moveToMenu); - this.add(moveSubcontactMenu); + add(moveToMenu); + add(moveSubcontactMenu); - this.addSeparator(); + addSeparator(); - this.add(addContactItem); + add(addContactItem); - this.addSeparator(); + addSeparator(); - this.add(removeContactMenu); - this.add(renameContactItem); + add(removeContactMenu); + add(renameContactItem); - this.addSeparator(); + addSeparator(); - this.add(viewHistoryItem); + add(viewHistoryItem); - this.initPluginComponents(); + initPluginComponents(); - this.sendMessageItem.setName("sendMessage"); + sendMessageItem.setName("sendMessage"); - this.sendSmsItem.setName("sendSms"); - this.sendFileItem.setName("sendFile"); - this.moveToMenu.setName("moveToGroup"); - this.addContactItem.setName("addContact"); - this.renameContactItem.setName("renameContact"); - this.viewHistoryItem.setName("viewHistory"); + sendSmsItem.setName("sendSms"); + sendFileItem.setName("sendFile"); + moveToMenu.setName("moveToGroup"); + addContactItem.setName("addContact"); + renameContactItem.setName("renameContact"); + viewHistoryItem.setName("viewHistory"); - this.sendMessageItem.addActionListener(this); - this.sendSmsItem.addActionListener(this); - this.sendFileItem.addActionListener(this); - this.renameContactItem.addActionListener(this); - this.viewHistoryItem.addActionListener(this); - this.addContactItem.addActionListener(this); + sendMessageItem.addActionListener(this); + sendSmsItem.addActionListener(this); + sendFileItem.addActionListener(this); + renameContactItem.addActionListener(this); + viewHistoryItem.addActionListener(this); + addContactItem.addActionListener(this); // Disable all menu items that do nothing. if (metaContact.getDefaultContact( @@ -466,7 +503,7 @@ public class MetaContactRightButtonMenu if (metaContact.getDefaultContact( OperationSetDesktopSharingServer.class) == null) - this.desktopSharingItem.setEnabled(false); + this.contactDesktopSharingMenu.setEnabled(false); if (metaContact.getDefaultContact( OperationSetBasicInstantMessaging.class) == null) @@ -577,13 +614,13 @@ public class MetaContactRightButtonMenu char desktopSharingMnemonic = GuiActivator.getResources() .getI18nMnemonic("service.gui.SHARE_DESKTOP"); - if (desktopSharingMenu.getItemCount() > 1) + if (contactDesktopSharingMenu.getItemCount() > 1) { - this.desktopSharingMenu.setMnemonic(desktopSharingMnemonic); + this.contactDesktopSharingMenu.setMnemonic(desktopSharingMnemonic); } else { - this.desktopSharingItem.setMnemonic(desktopSharingMnemonic); + this.contactDesktopSharingMenu.setMnemonic(desktopSharingMnemonic); } this.sendSmsItem.setMnemonic(GuiActivator.getResources() .getI18nMnemonic("service.gui.SEND_SMS")); @@ -650,7 +687,7 @@ public class MetaContactRightButtonMenu CallManager.createVideoCall( contact.getProtocolProvider(), contact.getAddress()); } - else if (itemName.equals("desktopSharing")) + else if (itemName.equals("shareFullScreen")) { contact = metaContact.getDefaultContact( OperationSetVideoTelephony.class); @@ -658,6 +695,14 @@ public class MetaContactRightButtonMenu CallManager.createDesktopSharing( contact.getProtocolProvider(), contact.getAddress()); } + else if (itemName.equals("shareRegion")) + { + contact = metaContact.getDefaultContact( + OperationSetVideoTelephony.class); + + CallManager.createRegionDesktopSharing( + contact.getProtocolProvider(), contact.getAddress()); + } else if (itemName.equals("sendFile")) { SipCommFileChooser scfc = GenericFileDialog.create( @@ -791,14 +836,23 @@ public class MetaContactRightButtonMenu CallManager.createVideoCall(contact.getProtocolProvider(), contact.getAddress()); } - else if (itemName.startsWith(desktopSharingPrefix)) + else if (itemName.startsWith(fullDesktopSharingPrefix)) { contact = getContactFromMetaContact( - itemName.substring(desktopSharingPrefix.length())); + itemName.substring(fullDesktopSharingPrefix.length())); CallManager.createDesktopSharing( contact.getProtocolProvider(), contact.getAddress()); } + else if (itemName.startsWith(regionDesktopSharingPrefix)) + { + contact = getContactFromMetaContact( + itemName.substring(regionDesktopSharingPrefix.length())); + + CallManager.createRegionDesktopSharing( + contact.getProtocolProvider(), + contact.getAddress()); + } } /** @@ -993,7 +1047,7 @@ public class MetaContactRightButtonMenu videoCallItem.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.VIDEO_CALL))); - desktopSharingItem.setIcon(new ImageIcon( + contactDesktopSharingMenu.setIcon(new ImageIcon( ImageLoader.getImage(ImageLoader.DESKTOP_SHARING))); sendMessageItem.setIcon(new ImageIcon( diff --git a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf index 3ea66ea..e7a8922 100644 --- a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf +++ b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf @@ -42,6 +42,7 @@ Import-Package: org.osgi.framework, net.java.sip.communicator.util.swing.event, net.java.sip.communicator.util.swing.plaf, net.java.sip.communicator.util.skin, + net.java.sip.communicator.util.swing.transparent, javax.accessibility, javax.imageio, javax.swing, diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java index d24078b..aa1d72b 100644 --- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java +++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java @@ -905,6 +905,12 @@ public class ImageLoader public static final ImageID VOLUME_CONTROL_BUTTON = new ImageID("service.gui.buttons.VOLUME_CONTROL"); + /** + * The transparent window button background. + */ + public static final ImageID TRANSPARENT_WINDOW_BUTTON + = new ImageID("service.gui.buttons.TRANSPARENT_WINDOW_BUTTON"); + /* * ======================================================================= * ------------------------ EDIT TOOLBAR ICONS --------------------------- diff --git a/src/net/java/sip/communicator/util/swing/transparent/AWTUtilitiesWrapper.java b/src/net/java/sip/communicator/util/swing/transparent/AWTUtilitiesWrapper.java new file mode 100644 index 0000000..2967ddd --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/transparent/AWTUtilitiesWrapper.java @@ -0,0 +1,170 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + * + * Based on the code of Anthony Petrov + * http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/ + */ +package net.java.sip.communicator.util.swing.transparent; + +import java.awt.GraphicsConfiguration; +import java.awt.Shape; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Yana Stamcheva + */ +public class AWTUtilitiesWrapper +{ + private static Class<?> awtUtilitiesClass; + private static Class<?> translucencyClass; + private static Method mIsTranslucencySupported, mIsTranslucencyCapable, + mSetWindowShape, mSetWindowOpacity, mSetWindowOpaque; + + public static Object PERPIXEL_TRANSPARENT, TRANSLUCENT, PERPIXEL_TRANSLUCENT; + + static void init() + { + try + { + awtUtilitiesClass = Class.forName("com.sun.awt.AWTUtilities"); + translucencyClass + = Class.forName("com.sun.awt.AWTUtilities$Translucency"); + + if (translucencyClass.isEnum()) + { + Object[] kinds = translucencyClass.getEnumConstants(); + if (kinds != null) + { + PERPIXEL_TRANSPARENT = kinds[0]; + TRANSLUCENT = kinds[1]; + PERPIXEL_TRANSLUCENT = kinds[2]; + } + } + mIsTranslucencySupported = awtUtilitiesClass.getMethod( + "isTranslucencySupported", translucencyClass); + mIsTranslucencyCapable = awtUtilitiesClass.getMethod( + "isTranslucencyCapable", GraphicsConfiguration.class); + mSetWindowShape = awtUtilitiesClass.getMethod( + "setWindowShape", Window.class, Shape.class); + mSetWindowOpacity = awtUtilitiesClass.getMethod( + "setWindowOpacity", Window.class, float.class); + mSetWindowOpaque = awtUtilitiesClass.getMethod( + "setWindowOpaque", Window.class, boolean.class); + } + catch (NoSuchMethodException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (SecurityException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (ClassNotFoundException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + static + { + init(); + } + + private static boolean isSupported(Method method, Object kind) + { + if (awtUtilitiesClass == null || method == null) + { + return false; + } + try + { + Object ret = method.invoke(null, kind); + if (ret instanceof Boolean) + { + return ((Boolean)ret).booleanValue(); + } + } + catch (IllegalAccessException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (IllegalArgumentException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (InvocationTargetException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + return false; + } + + public static boolean isTranslucencySupported(Object kind) + { + if (translucencyClass == null) + return false; + + return isSupported(mIsTranslucencySupported, kind); + } + + public static boolean isTranslucencyCapable(GraphicsConfiguration gc) + { + return isSupported(mIsTranslucencyCapable, gc); + } + + private static void set(Method method, Window window, Object value) + { + if (awtUtilitiesClass == null || method == null) + { + return; + } + try + { + method.invoke(null, window, value); + } + catch (IllegalAccessException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (IllegalArgumentException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + catch (InvocationTargetException ex) + { + Logger.getLogger(AWTUtilitiesWrapper.class.getName()) + .log(Level.SEVERE, null, ex); + } + } + + public static void setWindowShape(Window window, Shape shape) + { + set(mSetWindowShape, window, shape); + } + + public static void setWindowOpacity(Window window, float opacity) + { + set(mSetWindowOpacity, window, Float.valueOf(opacity)); + } + + public static void setWindowOpaque(Window window, boolean opaque) + { + set(mSetWindowOpaque, window, Boolean.valueOf(opaque)); + } +}
\ No newline at end of file diff --git a/src/net/java/sip/communicator/util/swing/transparent/TransparentFrame.java b/src/net/java/sip/communicator/util/swing/transparent/TransparentFrame.java new file mode 100644 index 0000000..f12916e --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/transparent/TransparentFrame.java @@ -0,0 +1,82 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util.swing.transparent; + +import java.awt.*; + +import javax.swing.*; + +/** + * + * @author Yana Stamcheva + */ +public class TransparentFrame + extends JFrame + implements RootPaneContainer +{ + /** + * Indicates if the transparency is supported from the current graphics + * environment. + */ + public static boolean isTranslucencySupported; + + /** + * Creates a transparent undecorated frame. If the transparency is not + * supported creates a normal undecorated frame. + * + * @return the created frame + */ + public static TransparentFrame createTransparentFrame() + { + isTranslucencySupported + = AWTUtilitiesWrapper.isTranslucencySupported( + AWTUtilitiesWrapper.PERPIXEL_TRANSLUCENT); + + GraphicsConfiguration translucencyCapableGC + = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + + if (!AWTUtilitiesWrapper.isTranslucencyCapable(translucencyCapableGC)) + { + translucencyCapableGC = null; + + GraphicsEnvironment env + = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] devices = env.getScreenDevices(); + + for (int i = 0; i < devices.length + && translucencyCapableGC == null; i++) + { + GraphicsConfiguration[] configs = devices[i].getConfigurations(); + for (int j = 0; j < configs.length + && translucencyCapableGC == null; j++) + { + if (AWTUtilitiesWrapper.isTranslucencyCapable(configs[j])) + { + translucencyCapableGC = configs[j]; + } + } + } + if (translucencyCapableGC == null) + { + isTranslucencySupported = false; + } + } + + return new TransparentFrame(translucencyCapableGC); + } + + /** Creates new form FancyFrame */ + private TransparentFrame(GraphicsConfiguration gc) + { + super(gc); + + setUndecorated(true); + AWTUtilitiesWrapper.setWindowOpaque(this, false); + AWTUtilitiesWrapper.setWindowOpacity(this, 1f); + } +} diff --git a/src/net/java/sip/communicator/util/util.manifest.mf b/src/net/java/sip/communicator/util/util.manifest.mf index 7726cd6..140fd43 100644 --- a/src/net/java/sip/communicator/util/util.manifest.mf +++ b/src/net/java/sip/communicator/util/util.manifest.mf @@ -35,11 +35,13 @@ Import-Package: org.xml.sax, net.java.sip.communicator.service.contactlist, sun.awt.shell, sun.net.util, - sun.net.dns + sun.net.dns, + com.sun.awt Export-Package: net.java.sip.communicator.util.xml, net.java.sip.communicator.util.swing.plaf, net.java.sip.communicator.util.swing.event, net.java.sip.communicator.util.swing, + net.java.sip.communicator.util.swing.transparent, net.java.sip.communicator.util.swing.border, net.java.sip.communicator.util, net.java.sip.communicator.util.skin, |