Changeset 18578 in vbox
- Timestamp:
- Mar 31, 2009 2:27:43 PM (15 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostServices/SharedClipboard/x11-clipboard.cpp
r18551 r18578 809 809 810 810 /** 811 * Initialise the host side of the shared clipboard. 812 * @todo This mixes host glue and X11 backend code, separate into two 813 * functions. 814 */ 815 int vboxClipboardInit (void) 811 * Initialise the X11 backend of the shared clipboard. 812 * @note X11 backend code 813 */ 814 int vboxClipboardInitBackend (void) 816 815 { 817 816 int rc; … … 824 823 * silently and report success on every call. This is important for VBoxHeadless. 825 824 */ 826 LogRelFunc((" no X11 detected -- host clipboard disabled\n"));825 LogRelFunc(("X11 DISPLAY variable not set -- disabling shared clipboard\n")); 827 826 g_fHaveX11 = false; 828 827 return VINF_SUCCESS; … … 852 851 g_fHaveX11 = true; 853 852 854 LogRel(("Initializing host clipboard service\n")); 855 RTSemEventCreate(&g_ctxHost.waitForData); 853 LogRel(("Initializing X11 clipboard backend\n")); 856 854 RTSemEventCreate(&g_ctxX11.waitForData); 857 RTSemMutexCreate(&g_ctxHost.clipboardMutex);858 855 rc = vboxClipboardInitX11(); 859 856 if (RT_SUCCESS(rc)) … … 862 859 RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "SHCLIP"); 863 860 if (RT_FAILURE(rc)) 864 LogRel(("Failed to start the host shared clipboard thread.\n"));861 LogRel(("Failed to initialise the shared clipboard X11 backend.\n")); 865 862 } 866 863 if (RT_FAILURE(rc)) 864 RTSemEventDestroy(g_ctxX11.waitForData); 865 return rc; 866 } 867 868 /** 869 * Initialise the host side of the shared clipboard. 870 * @note Host glue code 871 */ 872 int vboxClipboardInit (void) 873 { 874 int rc = VINF_SUCCESS; 875 LogRel(("Initializing host clipboard service\n")); 876 RTSemEventCreate(&g_ctxHost.waitForData); 877 RTSemMutexCreate(&g_ctxHost.clipboardMutex); 878 rc = vboxClipboardInitBackend(); 879 if (RT_FAILURE(rc)) 867 880 { 868 881 RTSemEventDestroy(g_ctxHost.waitForData); 869 RTSemEventDestroy(g_ctxX11.waitForData);870 882 RTSemMutexDestroy(g_ctxHost.clipboardMutex); 883 LogRel(("Failed to start the host shared clipboard service.\n")); 871 884 } 872 885 return rc; … … 874 887 875 888 /** 876 * Terminate the host side of the shared clipboard. 877 * @todo This mixes host glue and X11 backend code, separate into two 878 * functions. 879 */ 880 void vboxClipboardDestroy (void) 889 * Terminate the shared clipboard X11 backend. 890 * @note X11 backend code 891 */ 892 int vboxClipboardDestroyBackend (void) 881 893 { 882 894 int rc, rcThread; … … 888 900 */ 889 901 if (!g_fHaveX11) 890 return; 891 892 LogRel(("vboxClipboardDestroy: shutting down host clipboard\n")); 893 894 /* Drop the reference to the client, in case it is still there. This will 895 * cause any outstanding clipboard data requests from X11 to fail 896 * immediately. */ 897 g_ctxHost.pClient = NULL; 898 if (g_ctxX11.eOwner == VB) 899 /* X11 may be waiting for data from VBox. At this point it is no 900 * longer going to arrive, and we must release it to allow the event 901 * loop to terminate. In this case the buffer where VBox would have 902 * written the clipboard data will still be empty and we will just 903 * return "no data" to X11. Any subsequent attempts to get the data 904 * from VBox will fail immediately as the client reference is gone. */ 905 RTSemEventSignal(g_ctxHost.waitForData); 902 return VINF_SUCCESS; 903 904 LogRelFunc(("shutting down the shared clipboard X11 backend\n")); 905 906 906 /* Set the termination flag. This has been observed to block if it was set 907 907 * during a request for clipboard data coming from X11, so only we do it … … 922 922 if (RT_SUCCESS(rc)) 923 923 { 924 /* 925 * No one should be waiting on this by now. Justification: 926 * - Case 1: VBox is waiting for data from X11: 927 * Not possible, as it would be waiting on this thread. 928 * - Case 2: X11 is waiting for data from VBox: 929 * Not possible, as we checked that the X11 event thread exited 930 * successfully. 931 */ 932 RTSemEventDestroy(g_ctxHost.waitForData); 924 /* We can safely destroy this now, as only this thread ever waits 925 * for it. */ 933 926 RTSemEventDestroy(g_ctxX11.waitForData); 934 RTSemMutexDestroy(g_ctxHost.clipboardMutex);935 927 AssertRC(rcThread); 936 928 } … … 938 930 LogRel(("vboxClipboardDestroy: rc=%Rrc\n", rc)); 939 931 XtCloseDisplay(XtDisplay(g_ctxX11.widget)); 940 LogFlowFunc(("returning.\n")); 941 } 942 943 /** 944 * Connect a guest the shared clipboard. 945 * @todo This mixes host glue and X11 backend code, separate into two 946 * functions. 947 */ 948 int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient) 949 { 932 LogFlowFunc(("returning %Rrc.\n", rc)); 933 return rc; 934 } 935 936 /** 937 * Terminate the host side of the shared clipboard. 938 * @note host glue code 939 */ 940 void vboxClipboardDestroy (void) 941 { 942 int rc = VINF_SUCCESS; 943 LogRelFunc(("shutting down host clipboard\n")); 944 /* Drop the reference to the client, in case it is still there. This 945 * will cause any outstanding clipboard data requests from X11 to fail 946 * immediately. */ 947 g_ctxHost.pClient = NULL; 948 /* The backend may be waiting for data from VBox. At this point it is no 949 * longer going to arrive, and we must release it to allow the event 950 * loop to terminate. In this case the buffer where VBox would have 951 * written the clipboard data will still be empty and we will just 952 * return "no data" to the backend. Any subsequent attempts to get the 953 * data from VBox will fail immediately as the client reference is gone. 954 */ 955 /** @note This has been made unconditional, as it should do no harm 956 * even if we are not waiting. */ 957 RTSemEventSignal(g_ctxHost.waitForData); 958 rc = vboxClipboardDestroyBackend(); 959 if (RT_SUCCESS(rc)) 960 { 961 /* We can safely destroy these as the backend has exited 962 * successfully and no other calls from the host code should be 963 * forthcoming. */ 964 /** @todo move these two into a frontend proxy object that the 965 * backend can call. */ 966 /** @todo can the backend fail to exit successfully? What then? */ 967 RTSemEventDestroy(g_ctxHost.waitForData); 968 RTSemMutexDestroy(g_ctxHost.clipboardMutex); 969 } 970 } 971 972 /** 973 * Announce to the X11 backend that we are ready to start. 974 * @param owner who is the initial clipboard owner 975 */ 976 int vboxClipboardConnectBackend (enum g_eOwner owner) 977 { 978 LogFlowFunc(("\n")); 950 979 /* 951 980 * Immediately return if we are not connected to the host X server. … … 954 983 return VINF_SUCCESS; 955 984 956 LogFlow(("vboxClipboardConnect\n")); 957 985 g_ctxX11.eOwner = owner; 986 if (owner == X11) 987 g_ctxX11.notifyVBox = true; 988 else 989 { 990 /** @todo take ownership of the X11 clipboard. */ 991 } 992 return VINF_SUCCESS; 993 } 994 995 /** 996 * Connect a guest to the shared clipboard. 997 * @note host glue code 998 * @note on the host, we assume that some other application already owns 999 * the clipboard and leave ownership to X11. 1000 */ 1001 int vboxClipboardConnect (VBOXCLIPBOARDCLIENTDATA *pClient) 1002 { 1003 int rc = VINF_SUCCESS; 1004 LogFlowFunc(("\n")); 958 1005 /* Only one client is supported for now */ 959 1006 AssertLogRelReturn(g_ctxHost.pClient == 0, VERR_NOT_SUPPORTED); 960 961 1007 pClient->pCtx = &g_ctxHost; 962 1008 pClient->pCtx->pClient = pClient; 963 g_ctxX11.eOwner = X11; 964 g_ctxX11.notifyVBox = true; 965 return VINF_SUCCESS; 966 } 967 968 /** 969 * Synchronise the contents of the host clipboard with the guest, called 970 * after a save and restore of the guest. 971 * @todo This mixes host glue and X11 backend code and calls host frontend 972 * APIs. Separate into two functions. 973 */ 974 int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient) 975 { 976 /* 977 * Immediately return if we are not connected to the host X server. 978 */ 979 if (!g_fHaveX11) 980 return VINF_SUCCESS; 981 982 /* On a Linux host, the guest should never synchronise/cache its clipboard contents, as 983 we have no way of reliably telling when the host clipboard data changes. So instead 984 of synchronising, we tell the guest to empty its clipboard, and we set the cached 985 flag so that we report formats to the guest next time we poll for them. */ 986 vboxSvcClipboardReportMsg (g_ctxHost.pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0); 987 g_ctxX11.notifyVBox = true; 988 989 return VINF_SUCCESS; 990 } 991 992 /** 993 * Shut down the shared clipboard service and "disconnect" the guest. 994 * @todo This mixes host glue and X11 backend code, separate into two 995 * functions. 996 */ 997 void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *) 1009 /** The pClient pointer is a dummy anyway, as we only support a single 1010 * client at a time. */ 1011 rc = vboxClipboardConnectBackend(X11 /* initial owner */); 1012 return rc; 1013 } 1014 1015 /** 1016 * Called when the VBox may have fallen out of sync with the backend. 1017 * @note X11 backend code 1018 */ 1019 void vboxClipboardRequestSync (void) 998 1020 { 999 1021 /* … … 1002 1024 if (!g_fHaveX11) 1003 1025 return; 1004 1005 LogFlow(("vboxClipboardDisconnect\n")); 1006 1007 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 1008 g_ctxHost.pClient = NULL; 1026 g_ctxX11.notifyVBox = true; 1027 } 1028 1029 /** 1030 * Synchronise the contents of the host clipboard with the guest, called 1031 * after a save and restore of the guest. 1032 * @note Host glue code 1033 */ 1034 int vboxClipboardSync (VBOXCLIPBOARDCLIENTDATA *pClient) 1035 { 1036 1037 /* On a Linux host, the guest should never synchronise/cache its 1038 * clipboard contents, as we have no way of reliably telling when the 1039 * host clipboard data changes. So instead of synchronising, we tell 1040 * the guest to empty its clipboard, and we set the cached flag so that 1041 * we report formats to the guest next time we poll for them. */ 1042 /** @note This has been changed so that the message is sent even if 1043 * X11 is not available. */ 1044 vboxSvcClipboardReportMsg (g_ctxHost.pClient, 1045 VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, 0); 1046 vboxClipboardRequestSync(); 1047 1048 return VINF_SUCCESS; 1049 } 1050 1051 /** 1052 * Shut down the shared clipboard service and "disconnect" the guest. 1053 * @todo This mixes host glue and X11 backend code, separate into two 1054 * functions. 1055 */ 1056 void vboxClipboardDisconnectBackend (void) 1057 { 1058 /* 1059 * Immediately return if we are not connected to the host X server. 1060 */ 1061 if (!g_fHaveX11) 1062 return; 1063 1009 1064 g_ctxX11.eOwner = NONE; 1010 1065 g_ctxX11.X11TextFormat = INVALID; 1011 1066 g_ctxX11.X11BitmapFormat = INVALID; 1067 } 1068 1069 /** 1070 * Shut down the shared clipboard service and "disconnect" the guest. 1071 * @todo This mixes host glue and X11 backend code, separate into two 1072 * functions. 1073 */ 1074 void vboxClipboardDisconnect (VBOXCLIPBOARDCLIENTDATA *) 1075 { 1076 LogFlow(("vboxClipboardDisconnect\n")); 1077 1078 RTSemMutexRequest(g_ctxHost.clipboardMutex, RT_INDEFINITE_WAIT); 1079 g_ctxHost.pClient = NULL; 1080 vboxClipboardDisconnectBackend(); 1012 1081 RTSemMutexRelease(g_ctxHost.clipboardMutex); 1013 1082 } … … 1481 1550 * VBox is taking possession of the shared clipboard. 1482 1551 * 1483 * @param pClient Context data for the guest system1484 1552 * @param u32Formats Clipboard formats the guest is offering 1485 * @note Called by the HGCM clipboard service 1486 * @thread HGCM clipboard service thread 1487 */ 1488 void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats) 1553 * @note X11 backend code 1554 */ 1555 void vboxClipboardFormatAnnounceBackend (uint32_t u32Formats) 1489 1556 { 1490 1557 /* … … 1530 1597 1531 1598 /** 1599 * VBox is taking possession of the shared clipboard. 1600 * 1601 * @param pClient Context data for the guest system 1602 * @param u32Formats Clipboard formats the guest is offering 1603 * @note Host glue code 1604 */ 1605 void vboxClipboardFormatAnnounce (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Formats) 1606 { 1607 vboxClipboardFormatAnnounceBackend (u32Formats); 1608 } 1609 1610 /** 1611 * Called when VBox wants to read the X11 clipboard. 1612 * 1613 * @param pClient Context information about the guest VM 1614 * @param u32Format The format that the guest would like to receive the data in 1615 * @param pv Where to write the data to 1616 * @param cb The size of the buffer to write the data to 1617 * @param pcbActual Where to write the actual size of the written data 1618 * @note X11 backend code 1619 */ 1620 int vboxClipboardReadDataBackend (uint32_t u32Format, 1621 VBOXCLIPBOARDREQUEST *pRequest) 1622 { 1623 /* 1624 * Immediately return if we are not connected to the host X server. 1625 */ 1626 if (!g_fHaveX11) 1627 { 1628 /* no data available */ 1629 *pRequest->pcbActual = 0; 1630 return VINF_SUCCESS; 1631 } 1632 1633 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, pRequest->cb)); 1634 1635 /* 1636 * The guest wants to read data in the given format. 1637 */ 1638 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1639 { 1640 if (g_ctxX11.X11TextFormat == INVALID) 1641 { 1642 /* No data available. */ 1643 *pRequest->pcbActual = 0; 1644 return VERR_NO_DATA; /* The guest thinks we have data and we don't */ 1645 } 1646 /* Initially set the size of the data read to zero in case we fail 1647 * somewhere. */ 1648 *pRequest->pcbActual = 0; 1649 /* Send out a request for the data to the current clipboard owner */ 1650 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard, 1651 g_ctxX11.atomX11TextFormat, 1652 vboxClipboardGetDataFromX11, 1653 reinterpret_cast<XtPointer>(pRequest), 1654 CurrentTime); 1655 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The 1656 callback will signal the event semaphore when it has processed the data for us. */ 1657 1658 int rc = RTSemEventWait(g_ctxX11.waitForData, RT_INDEFINITE_WAIT); 1659 if (RT_FAILURE(rc)) 1660 return rc; 1661 } 1662 else 1663 { 1664 return VERR_NOT_IMPLEMENTED; 1665 } 1666 return VINF_SUCCESS; 1667 } 1668 1669 /** 1532 1670 * Called when VBox wants to read the X11 clipboard. 1533 1671 * … … 1538 1676 * @param pcbActual Where to write the actual size of the written data 1539 1677 * @note Host glue code 1540 * @todo Separate this into a host and an X11-specific function1541 1678 */ 1542 1679 int vboxClipboardReadData (VBOXCLIPBOARDCLIENTDATA *pClient, … … 1544 1681 uint32_t *pcbActual) 1545 1682 { 1683 int rc = VINF_SUCCESS; 1546 1684 VBOXCLIPBOARDREQUEST request; 1547 /* 1548 * Immediately return if we are not connected to the host X server. 1549 */ 1550 if (!g_fHaveX11) 1551 { 1552 /* no data available */ 1553 *pcbActual = 0; 1554 return VINF_SUCCESS; 1555 } 1556 1557 LogFlowFunc (("u32Format = %d, cb = %d\n", u32Format, cb)); 1558 1559 /* 1560 * The guest wants to read data in the given format. 1561 */ 1562 if (u32Format & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT) 1563 { 1564 if (g_ctxX11.X11TextFormat == INVALID) 1565 { 1566 /* No data available. */ 1567 *pcbActual = 0; 1568 return VERR_NO_DATA; /* The guest thinks we have data and we don't */ 1569 } 1570 /* No one else (VBox or X11) should currently be waiting. The first because 1571 * requests from VBox are serialised and the second because X11 previously 1572 * grabbed the clipboard, so it should not be waiting for data from us. */ 1573 AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctxHost.waiter, VB, NONE), VERR_DEADLOCK); 1574 request.pv = pv; 1575 request.cb = cb; 1576 request.pcbActual = pcbActual; 1577 /* Initially set the size of the data read to zero in case we fail 1578 * somewhere. */ 1579 *pcbActual = 0; 1580 /* Send out a request for the data to the current clipboard owner */ 1581 XtGetSelectionValue(g_ctxX11.widget, g_ctxX11.atomClipboard, 1582 g_ctxX11.atomX11TextFormat, 1583 vboxClipboardGetDataFromX11, 1584 reinterpret_cast<XtPointer>(&request), 1585 CurrentTime); 1586 /* When the data arrives, the vboxClipboardGetDataFromX11 callback will be called. The 1587 callback will signal the event semaphore when it has processed the data for us. */ 1588 1589 int rc = RTSemEventWait(g_ctxX11.waitForData, RT_INDEFINITE_WAIT); 1590 if (RT_FAILURE(rc)) 1591 { 1592 g_ctxHost.waiter = NONE; 1593 return rc; 1594 } 1595 g_ctxHost.waiter = NONE; 1596 } 1597 else 1598 { 1599 return VERR_NOT_IMPLEMENTED; 1600 } 1601 return VINF_SUCCESS; 1685 /* No one else (VBox or X11) should currently be waiting. The first 1686 * because requests from VBox are serialised and the second because X11 1687 * previously grabbed the clipboard, so it should not be waiting for 1688 * data from us. */ 1689 AssertLogRelReturn (ASMAtomicCmpXchgU32(&g_ctxHost.waiter, VB, NONE), 1690 VERR_DEADLOCK); 1691 request.pv = pv; 1692 request.cb = cb; 1693 request.pcbActual = pcbActual; 1694 rc = vboxClipboardReadDataBackend(u32Format, &request); 1695 g_ctxHost.waiter = NONE; 1696 return rc; 1602 1697 } 1603 1698
Note:
See TracChangeset
for help on using the changeset viewer.

