/** Determine the title to display for a client. */ void ReadWMName(ClientNode *np) { unsigned long count; int status; unsigned long extra; Atom realType; int realFormat; unsigned char *name; if(np->name) { Release(np->name); } status = JXGetWindowProperty(display, np->window, atoms[ATOM_NET_WM_NAME], 0, 1024, False, atoms[ATOM_UTF8_STRING], &realType, &realFormat, &count, &extra, &name); if(status != Success || realFormat == 0) { np->name = NULL; } else { const size_t size = strlen((char*)name) + 1; np->name = Allocate(size); memcpy(np->name, name, size); JXFree(name); np->name = ConvertFromUTF8(np->name); } #ifdef USE_XUTF8 if(!np->name) { status = JXGetWindowProperty(display, np->window, XA_WM_NAME, 0, 1024, False, atoms[ATOM_COMPOUND_TEXT], &realType, &realFormat, &count, &extra, &name); if(status == Success && realFormat == 8) { char **tlist; XTextProperty tprop; int tcount; tprop.value = name; tprop.encoding = atoms[ATOM_COMPOUND_TEXT]; tprop.format = realFormat; tprop.nitems = strlen((char*)name); if(XmbTextPropertyToTextList(display, &tprop, &tlist, &tcount) == Success && tcount > 0) { const size_t len = strlen(tlist[0]) + 1; np->name = Allocate(len); memcpy(np->name, tlist[0], len); XFreeStringList(tlist); } JXFree(name); } } #endif if(!np->name) { char *temp = NULL; if(JXFetchName(display, np->window, &temp)) { const size_t len = strlen(temp) + 1; np->name = Allocate(len); memcpy(np->name, temp, len); JXFree(temp); } } }
std::string XWindowManager::GetStringProperty(Window window_id, Atom atom) const { Atom type; int result, format; unsigned long n_items, bytes_after; char *val = nullptr; result = XGetWindowProperty(screen->dpy(), window_id, atom, 0L, 65536, False, AnyPropertyType, &type, &format, &n_items, &bytes_after, reinterpret_cast<unsigned char **>(&val)); if (result != Success) { LOG_DEBUG(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << " for window " << window_id; return std::string(); } if (!val || n_items == 0) { LOG_DEBUG(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << " for window " << window_id << ": empty value"; return std::string(); } std::unique_ptr<char[], int(*)(void*)> string(val, XFree); if (format != 8) { LOG_ERROR(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << " for window " << window_id << ": invalid format " << format; return std::string(); } if (type != XA_STRING && type != atom::XA_COMPOUND_TEXT && type != Atoms::utf8String) { LOG_ERROR(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << " for window " << window_id << ": invalid string type: " << gdk_x11_get_xatom_name(type); return std::string(); } if (type == atom::XA_COMPOUND_TEXT || (type == XA_STRING && !g_utf8_validate(val, n_items, nullptr))) { // In case we have compound text, we need to convert it to utf-8 XTextProperty text_property; text_property.value = reinterpret_cast<unsigned char*>(val); text_property.encoding = type; text_property.format = format; text_property.nitems = n_items; char **list = nullptr; int count = 0; result = XmbTextPropertyToTextList(screen->dpy(), &text_property, &list, &count); if (result != Success || count == 0) { LOG_WARN(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << "for window " << window_id << " properly: impossible to convert to current locale"; return std::string(val, n_items); } std::unique_ptr<char*[], void(*)(char**)> list_ptr(list, XFreeStringList); if (count != 1) { LOG_WARN(logger) << "Impossible to get the property " << gdk_x11_get_xatom_name(atom) << "for window " << window_id << " properly: invalid number of parsed values"; } return list_ptr[0]; } return std::string(val, n_items); }
/*ARGSUSED*/ static void InsertClipboard(Widget w, XtPointer client_data, Atom *selection, Atom *type, XtPointer value, unsigned long *length, int *format) { Display *d = XtDisplay(w); Atom target = (Atom)client_data; Boolean convert_failed = (*type == XT_CONVERT_FAIL); if (!convert_failed) { char **list; int i, ret, count; XTextProperty prop; prop.value = value; prop.nitems = *length; prop.format = *format; prop.encoding = *type; ret = XmbTextPropertyToTextList(d, &prop, &list, &count); if (ret >= Success) { /* manuals say something about multiple strings in a disjoint text selection (?), it should be harmless to get them all */ for (i = 0; i < count; i++) NewCurrentClipContents(list[i], strlen(list[i])); XFreeStringList(list); } else convert_failed = True; XFree(value); } if (convert_failed) { /* if UTF8_STRING failed try COMPOUND_TEXT */ if (target == XA_UTF8_STRING(d)) { XtGetSelectionValue(w, *selection, XA_COMPOUND_TEXT(d), InsertClipboard, (XtPointer)(XA_COMPOUND_TEXT(d)), CurrentTime); return; } /* if COMPOUND_TEXT failed try STRING */ else if (target == XA_COMPOUND_TEXT(d)) { XtGetSelectionValue(w, *selection, XA_STRING, InsertClipboard, NULL, CurrentTime); return; } /* all conversions failed */ else { Arg arg; XtSetArg (arg, XtNlabel, "CLIPBOARD selection conversion failed"); XtSetValues (failDialog, &arg, 1); CenterWidgetOnWidget (failDialogShell, text); XtPopup (failDialogShell, XtGrabNone); #ifdef XKB XkbStdBell (d, XtWindow(w), 0, XkbBI_MinorError); #else XBell (d, 0); #endif } } XtOwnSelection(top, ClipboardAtom, CurrentTime, ConvertSelection, LoseSelection, NULL); }
int winClipboardFlushXEvents (HWND hwnd, int iWindow, Display *pDisplay, Bool fUseUnicode) { static Atom atomLocalProperty; static Atom atomCompoundText; static Atom atomUTF8String; static Atom atomTargets; static int generation; if (generation != serverGeneration) { generation = serverGeneration; atomLocalProperty = XInternAtom (pDisplay, WIN_LOCAL_PROPERTY, False); atomUTF8String = XInternAtom (pDisplay, "UTF8_STRING", False); atomCompoundText = XInternAtom (pDisplay, "COMPOUND_TEXT", False); atomTargets = XInternAtom (pDisplay, "TARGETS", False); } /* Process all pending events */ while (XPending (pDisplay)) { XTextProperty xtpText = {0}; XEvent event; XSelectionEvent eventSelection; unsigned long ulReturnBytesLeft; char *pszReturnData = NULL; char *pszGlobalData = NULL; int iReturn; HGLOBAL hGlobal = NULL; XICCEncodingStyle xiccesStyle; int iConvertDataLen = 0; char *pszConvertData = NULL; char *pszTextList[2] = {NULL}; int iCount; char **ppszTextList = NULL; wchar_t *pwszUnicodeStr = NULL; int iUnicodeLen = 0; int iReturnDataLen = 0; int i; Bool fAbort = FALSE; Bool fCloseClipboard = FALSE; Bool fSetClipboardData = TRUE; /* Get the next event - will not block because one is ready */ XNextEvent (pDisplay, &event); /* Branch on the event type */ switch (event.type) { /* * SelectionRequest */ case SelectionRequest: { char *pszAtomName = NULL; winDebug("SelectionRequest - target %d\n", event.xselectionrequest.target); pszAtomName = XGetAtomName (pDisplay, event.xselectionrequest.target); winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); XFree (pszAtomName); pszAtomName = NULL; } /* Abort if invalid target type */ if (event.xselectionrequest.target != XA_STRING && event.xselectionrequest.target != atomUTF8String && event.xselectionrequest.target != atomCompoundText && event.xselectionrequest.target != atomTargets) { /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Handle targets type of request */ if (event.xselectionrequest.target == atomTargets) { Atom atomTargetArr[] = {atomTargets, atomCompoundText, atomUTF8String, XA_STRING}; /* Try to change the property */ iReturn = XChangeProperty (pDisplay, event.xselectionrequest.requestor, event.xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) atomTargetArr, (sizeof (atomTargetArr) / sizeof (atomTargetArr[0]))); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "XChangeProperty failed: %d\n", iReturn); } /* Setup selection notify xevent */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = event.xselectionrequest.property; eventSelection.time = event.xselectionrequest.time; /* * Notify the requesting window that * the operation has completed */ iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed\n"); } break; } /* Check that clipboard format is available */ if (fUseUnicode && !IsClipboardFormatAvailable (CF_UNICODETEXT)) { static int count; /* Hack to stop acroread spamming the log */ static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ if (hwnd != lasthwnd) count = 0; count++; if (count < 6) ErrorF ("winClipboardFlushXEvents - CF_UNICODETEXT is not " "available from Win32 clipboard. Aborting %d.\n", count); lasthwnd = hwnd; /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } else if (!fUseUnicode && !IsClipboardFormatAvailable (CF_TEXT)) { ErrorF ("winClipboardFlushXEvents - CF_TEXT is not " "available from Win32 clipboard. Aborting.\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Close clipboard if we have it open already */ if (GetOpenClipboardWindow () == hwnd) { CloseClipboard (); } /* Access the clipboard */ if (!OpenClipboard (hwnd)) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "OpenClipboard () failed: %08lx\n", GetLastError ()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Indicate that clipboard was opened */ fCloseClipboard = TRUE; /* Setup the string style */ if (event.xselectionrequest.target == XA_STRING) xiccesStyle = XStringStyle; #ifdef X_HAVE_UTF8_STRING else if (event.xselectionrequest.target == atomUTF8String) xiccesStyle = XUTF8StringStyle; #endif else if (event.xselectionrequest.target == atomCompoundText) xiccesStyle = XCompoundTextStyle; else xiccesStyle = XStringStyle; /* * FIXME: Can't pass CF_UNICODETEXT on Windows 95/98/Me */ /* Get a pointer to the clipboard text, in desired format */ if (fUseUnicode) { /* Retrieve clipboard data */ hGlobal = GetClipboardData (CF_UNICODETEXT); } else { /* Retrieve clipboard data */ hGlobal = GetClipboardData (CF_TEXT); } if (!hGlobal) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "GetClipboardData () failed: %08lx\n", GetLastError ()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } pszGlobalData = (char *) GlobalLock (hGlobal); /* Convert the Unicode string to UTF8 (MBCS) */ if (fUseUnicode) { iConvertDataLen = WideCharToMultiByte (CP_UTF8, 0, (LPCWSTR)pszGlobalData, -1, NULL, 0, NULL, NULL); /* NOTE: iConvertDataLen includes space for null terminator */ pszConvertData = (char *) malloc (iConvertDataLen); WideCharToMultiByte (CP_UTF8, 0, (LPCWSTR)pszGlobalData, -1, pszConvertData, iConvertDataLen, NULL, NULL); } else { pszConvertData = strdup (pszGlobalData); iConvertDataLen = strlen (pszConvertData) + 1; } /* Convert DOS string to UNIX string */ winClipboardDOStoUNIX (pszConvertData, strlen (pszConvertData)); /* Setup our text list */ pszTextList[0] = pszConvertData; pszTextList[1] = NULL; /* Initialize the text property */ xtpText.value = NULL; xtpText.nitems = 0; /* Create the text property from the text list */ if (fUseUnicode) { #ifdef X_HAVE_UTF8_STRING iReturn = Xutf8TextListToTextProperty (pDisplay, pszTextList, 1, xiccesStyle, &xtpText); #endif } else { iReturn = XmbTextListToTextProperty (pDisplay, pszTextList, 1, xiccesStyle, &xtpText); } if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "X*TextListToTextProperty failed: %d\n", iReturn); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Free the converted string */ free (pszConvertData); pszConvertData = NULL; /* Copy the clipboard text to the requesting window */ iReturn = XChangeProperty (pDisplay, event.xselectionrequest.requestor, event.xselectionrequest.property, event.xselectionrequest.target, 8, PropModeReplace, xtpText.value, xtpText.nitems); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "XChangeProperty failed: %d\n", iReturn); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Release the clipboard data */ GlobalUnlock (hGlobal); pszGlobalData = NULL; fCloseClipboard = FALSE; CloseClipboard (); /* Clean up */ XFree (xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; /* Setup selection notify event */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = event.xselectionrequest.property; eventSelection.time = event.xselectionrequest.time; /* Notify the requesting window that the operation has completed */ iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } winClipboardFlushXEvents_SelectionRequest_Done: /* Free allocated resources */ if (xtpText.value) { XFree (xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; } free(pszConvertData); if (hGlobal && pszGlobalData) GlobalUnlock (hGlobal); /* * Send a SelectionNotify event to the requesting * client when we abort. */ if (fAbort) { /* Setup selection notify event */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = None; eventSelection.time = event.xselectionrequest.time; /* Notify the requesting window that the operation is complete */ iReturn = XSendEvent (pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { /* * Should not be a problem if XSendEvent fails because * the client may simply have exited. */ ErrorF ("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed for abort event.\n"); } } /* Close clipboard if it was opened */ if (fCloseClipboard) { fCloseClipboard = FALSE; CloseClipboard (); } break; /* * SelectionNotify */ case SelectionNotify: winDebug ("winClipboardFlushXEvents - SelectionNotify\n"); { char *pszAtomName; pszAtomName = XGetAtomName (pDisplay, event.xselection.selection); winDebug("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName); XFree (pszAtomName); } /* * Request conversion of UTF8 and CompoundText targets. */ if (event.xselection.property == None) { if (event.xselection.target == XA_STRING) { winDebug ("winClipboardFlushXEvents - SelectionNotify - " "XA_STRING\n"); return WIN_XEVENTS_CONVERT; } else if (event.xselection.target == atomUTF8String) { winDebug("winClipboardFlushXEvents - SelectionNotify - " "Requesting conversion of UTF8 target.\n"); XConvertSelection (pDisplay, event.xselection.selection, XA_STRING, atomLocalProperty, iWindow, CurrentTime); /* Process the ConvertSelection event */ XFlush (pDisplay); return WIN_XEVENTS_CONVERT; } #ifdef X_HAVE_UTF8_STRING else if (event.xselection.target == atomCompoundText) { winDebug("winClipboardFlushXEvents - SelectionNotify - " "Requesting conversion of CompoundText target.\n"); XConvertSelection (pDisplay, event.xselection.selection, atomUTF8String, atomLocalProperty, iWindow, CurrentTime); /* Process the ConvertSelection event */ XFlush (pDisplay); return WIN_XEVENTS_CONVERT; } #endif else { ErrorF ("winClipboardFlushXEvents - SelectionNotify - " "Unknown format. Cannot request conversion, " "aborting.\n"); break; } } /* Retrieve the size of the stored data */ iReturn = XGetWindowProperty (pDisplay, iWindow, atomLocalProperty, 0, 0, /* Don't get data, just size */ False, AnyPropertyType, &xtpText.encoding, &xtpText.format, &xtpText.nitems, &ulReturnBytesLeft, &xtpText.value); if (iReturn != Success) { ErrorF ("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed, aborting: %d\n", iReturn); break; } winDebug("SelectionNotify - returned data %d left %d\n", xtpText.nitems, ulReturnBytesLeft); /* Request the selection data */ iReturn = XGetWindowProperty (pDisplay, iWindow, atomLocalProperty, 0, ulReturnBytesLeft, False, AnyPropertyType, &xtpText.encoding, &xtpText.format, &xtpText.nitems, &ulReturnBytesLeft, &xtpText.value); if (iReturn != Success) { ErrorF ("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed, aborting: %d\n", iReturn); break; } { char *pszAtomName = NULL; winDebug("SelectionNotify - returned data %d left %d\n", xtpText.nitems, ulReturnBytesLeft); pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); winDebug("Notify atom name %s\n", pszAtomName); XFree (pszAtomName); pszAtomName = NULL; } if (fUseUnicode) { #ifdef X_HAVE_UTF8_STRING /* Convert the text property to a text list */ iReturn = Xutf8TextPropertyToTextList (pDisplay, &xtpText, &ppszTextList, &iCount); #endif } else { iReturn = XmbTextPropertyToTextList (pDisplay, &xtpText, &ppszTextList, &iCount); } if (iReturn == Success || iReturn > 0) { /* Conversion succeeded or some unconvertible characters */ if (ppszTextList != NULL) { iReturnDataLen = 0; for (i = 0; i < iCount; i++) { iReturnDataLen += strlen(ppszTextList[i]); } pszReturnData = malloc (iReturnDataLen + 1); pszReturnData[0] = '\0'; for (i = 0; i < iCount; i++) { strcat (pszReturnData, ppszTextList[i]); } } else { ErrorF ("winClipboardFlushXEvents - SelectionNotify - " "X*TextPropertyToTextList list_return is NULL.\n"); pszReturnData = malloc (1); pszReturnData[0] = '\0'; } } else { ErrorF ("winClipboardFlushXEvents - SelectionNotify - " "X*TextPropertyToTextList returned: "); switch (iReturn) { case XNoMemory: ErrorF ("XNoMemory\n"); break; case XConverterNotFound: ErrorF ("XConverterNotFound\n"); break; default: ErrorF ("%d", iReturn); break; } pszReturnData = malloc (1); pszReturnData[0] = '\0'; } /* Free the data returned from XGetWindowProperty */ if (ppszTextList) XFreeStringList (ppszTextList); ppszTextList = NULL; XFree (xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; /* Convert the X clipboard string to DOS format */ winClipboardUNIXtoDOS (&pszReturnData, strlen (pszReturnData)); if (fUseUnicode) { /* Find out how much space needed to convert MBCS to Unicode */ iUnicodeLen = MultiByteToWideChar (CP_UTF8, 0, pszReturnData, -1, NULL, 0); /* Allocate memory for the Unicode string */ pwszUnicodeStr = (wchar_t*) malloc (sizeof (wchar_t) * (iUnicodeLen + 1)); if (!pwszUnicodeStr) { ErrorF ("winClipboardFlushXEvents - SelectionNotify " "malloc failed for pwszUnicodeStr, aborting.\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Do the actual conversion */ MultiByteToWideChar (CP_UTF8, 0, pszReturnData, -1, pwszUnicodeStr, iUnicodeLen); /* Allocate global memory for the X clipboard data */ hGlobal = GlobalAlloc (GMEM_MOVEABLE, sizeof (wchar_t) * (iUnicodeLen + 1)); } else { pszConvertData = strdup (pszReturnData); iConvertDataLen = strlen (pszConvertData) + 1; /* Allocate global memory for the X clipboard data */ hGlobal = GlobalAlloc (GMEM_MOVEABLE, iConvertDataLen); } free (pszReturnData); /* Check that global memory was allocated */ if (!hGlobal) { ErrorF ("winClipboardFlushXEvents - SelectionNotify " "GlobalAlloc failed, aborting: %ld\n", GetLastError ()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Obtain a pointer to the global memory */ pszGlobalData = GlobalLock (hGlobal); if (pszGlobalData == NULL) { ErrorF ("winClipboardFlushXEvents - Could not lock global " "memory for clipboard transfer\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Copy the returned string into the global memory */ if (fUseUnicode) { memcpy (pszGlobalData, pwszUnicodeStr, sizeof (wchar_t) * (iUnicodeLen + 1)); free (pwszUnicodeStr); pwszUnicodeStr = NULL; } else { strcpy (pszGlobalData, pszConvertData); free (pszConvertData); pszConvertData = NULL; } /* Release the pointer to the global memory */ GlobalUnlock (hGlobal); pszGlobalData = NULL; /* Push the selection data to the Windows clipboard */ if (fUseUnicode) SetClipboardData (CF_UNICODETEXT, hGlobal); else SetClipboardData (CF_TEXT, hGlobal); /* Flag that SetClipboardData has been called */ fSetClipboardData = FALSE; /* * NOTE: Do not try to free pszGlobalData, it is owned by * Windows after the call to SetClipboardData (). */ winClipboardFlushXEvents_SelectionNotify_Done: /* Free allocated resources */ if (ppszTextList) XFreeStringList (ppszTextList); if (xtpText.value) { XFree (xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; } free(pszConvertData); free(pwszUnicodeStr); if (hGlobal && pszGlobalData) GlobalUnlock (hGlobal); if (fSetClipboardData && g_fUnicodeSupport) SetClipboardData (CF_UNICODETEXT, NULL); if (fSetClipboardData) SetClipboardData (CF_TEXT, NULL); return WIN_XEVENTS_NOTIFY; case SelectionClear: winDebug("SelectionClear - doing nothing\n"); break; case PropertyNotify: break; case MappingNotify: break; default: ErrorF ("winClipboardFlushXEvents - unexpected event type %d\n", event.type); break; } } return WIN_XEVENTS_SUCCESS; }
QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist) { QString title; Atom type; int format; unsigned long nitems; unsigned long after; unsigned char* data = nullptr; // the window manager spec says we should read _NET_WM_NAME first, then fall back to WM_NAME int retVal = XGetWindowProperty(m_dpy, window, m_atomNetWmName, 0, 1000, false, m_atomUtf8String, &type, &format, &nitems, &after, &data); if ((retVal == 0) && data) { title = QString::fromUtf8(reinterpret_cast<char*>(data)); } else { XTextProperty textProp; retVal = XGetTextProperty(m_dpy, window, &textProp, m_atomWmName); if ((retVal != 0) && textProp.value) { char** textList = nullptr; int count; if (textProp.encoding == m_atomUtf8String) { title = QString::fromUtf8(reinterpret_cast<char*>(textProp.value)); } else if ((XmbTextPropertyToTextList(m_dpy, &textProp, &textList, &count) == 0) && textList && (count > 0)) { title = QString::fromLocal8Bit(textList[0]); } else if (textProp.encoding == m_atomString) { title = QString::fromLocal8Bit(reinterpret_cast<char*>(textProp.value)); } if (textList) { XFreeStringList(textList); } } if (textProp.value) { XFree(textProp.value); } } if (data) { XFree(data); } if (useBlacklist && !title.isEmpty()) { if (window == m_rootWindow) { return QString(); } QString className = windowClassName(window); if (m_classBlacklist.contains(className)) { return QString(); } QList<Window> keepassxWindows = widgetsToX11Windows(QApplication::topLevelWidgets()); if (keepassxWindows.contains(window)) { return QString(); } } return title; }
bool QX11Data::clipboardReadProperty(Window win, Atom property, bool deleteProperty, QByteArray *buffer, int *size, Atom *type, int *format) { int maxsize = maxSelectionIncr(display); ulong bytes_left; // bytes_after ulong length; // nitems uchar *data; Atom dummy_type; int dummy_format; int r; if (!type) // allow null args type = &dummy_type; if (!format) format = &dummy_format; // Don't read anything, just get the size of the property data r = XGetWindowProperty(display, win, property, 0, 0, False, AnyPropertyType, type, format, &length, &bytes_left, &data); if (r != Success || (type && *type == XNone)) { buffer->resize(0); return false; } XFree((char*)data); int offset = 0, buffer_offset = 0, format_inc = 1, proplen = bytes_left; VDEBUG("QClipboard: read_property(): initial property length: %d", proplen); switch (*format) { case 8: default: format_inc = sizeof(char) / 1; break; case 16: format_inc = sizeof(short) / 2; proplen *= sizeof(short) / 2; break; case 32: format_inc = sizeof(long) / 4; proplen *= sizeof(long) / 4; break; } int newSize = proplen; buffer->resize(newSize); bool ok = (buffer->size() == newSize); VDEBUG("QClipboard: read_property(): buffer resized to %d", buffer->size()); if (ok && newSize) { // could allocate buffer while (bytes_left) { // more to read... r = XGetWindowProperty(display, win, property, offset, maxsize/4, False, AnyPropertyType, type, format, &length, &bytes_left, &data); if (r != Success || (type && *type == XNone)) break; offset += length / (32 / *format); length *= format_inc * (*format) / 8; // Here we check if we get a buffer overflow and tries to // recover -- this shouldn't normally happen, but it doesn't // hurt to be defensive if ((int)(buffer_offset + length) > buffer->size()) { length = buffer->size() - buffer_offset; // escape loop bytes_left = 0; } memcpy(buffer->data() + buffer_offset, data, length); buffer_offset += length; XFree((char*)data); } if (*format == 8 && *type == ATOM(COMPOUND_TEXT)) { // convert COMPOUND_TEXT to a multibyte string XTextProperty textprop; textprop.encoding = *type; textprop.format = *format; textprop.nitems = buffer_offset; textprop.value = (unsigned char *) buffer->data(); char **list_ret = 0; int count; if (XmbTextPropertyToTextList(display, &textprop, &list_ret, &count) == Success && count && list_ret) { offset = buffer_offset = strlen(list_ret[0]); buffer->resize(offset); memcpy(buffer->data(), list_ret[0], offset); } if (list_ret) XFreeStringList(list_ret); } } // correct size, not 0-term. if (size) *size = buffer_offset; VDEBUG("QClipboard: read_property(): buffer size %d, buffer offset %d, offset %d", buffer->size(), buffer_offset, offset); if (deleteProperty) XDeleteProperty(display, win, property); XFlush(display); return ok; }
int winClipboardFlushXEvents(HWND hwnd, Window iWindow, Display * pDisplay, ClipboardConversionData *data, ClipboardAtoms *atoms) { Atom atomClipboard = atoms->atomClipboard; Atom atomLocalProperty = atoms->atomLocalProperty; Atom atomUTF8String = atoms->atomUTF8String; Atom atomCompoundText = atoms->atomCompoundText; Atom atomTargets = atoms->atomTargets; /* Process all pending events */ while (XPending(pDisplay)) { XTextProperty xtpText = { 0 }; XEvent event; XSelectionEvent eventSelection; unsigned long ulReturnBytesLeft; char *pszReturnData = NULL; char *pszGlobalData = NULL; int iReturn; HGLOBAL hGlobal = NULL; XICCEncodingStyle xiccesStyle; char *pszConvertData = NULL; char *pszTextList[2] = { NULL }; int iCount; char **ppszTextList = NULL; wchar_t *pwszUnicodeStr = NULL; Bool fAbort = FALSE; Bool fCloseClipboard = FALSE; Bool fSetClipboardData = TRUE; /* Get the next event - will not block because one is ready */ XNextEvent(pDisplay, &event); /* Branch on the event type */ switch (event.type) { /* * SelectionRequest */ case SelectionRequest: { char *pszAtomName = NULL; winDebug("SelectionRequest - target %ld\n", event.xselectionrequest.target); pszAtomName = XGetAtomName(pDisplay, event.xselectionrequest.target); winDebug("SelectionRequest - Target atom name %s\n", pszAtomName); XFree(pszAtomName); pszAtomName = NULL; } /* Abort if invalid target type */ if (event.xselectionrequest.target != XA_STRING && event.xselectionrequest.target != atomUTF8String && event.xselectionrequest.target != atomCompoundText && event.xselectionrequest.target != atomTargets) { /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Handle targets type of request */ if (event.xselectionrequest.target == atomTargets) { Atom atomTargetArr[] = { atomTargets, atomCompoundText, atomUTF8String, XA_STRING }; /* Try to change the property */ iReturn = XChangeProperty(pDisplay, event.xselectionrequest.requestor, event.xselectionrequest.property, XA_ATOM, 32, PropModeReplace, (unsigned char *) atomTargetArr, ARRAY_SIZE(atomTargetArr)); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "XChangeProperty failed: %d\n", iReturn); } /* Setup selection notify xevent */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = event.xselectionrequest.property; eventSelection.time = event.xselectionrequest.time; /* * Notify the requesting window that * the operation has completed */ iReturn = XSendEvent(pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed\n"); } break; } /* Close clipboard if we have it open already */ if (GetOpenClipboardWindow() == hwnd) { CloseClipboard(); } /* Access the clipboard */ if (!OpenClipboard(hwnd)) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "OpenClipboard () failed: %08x\n", (unsigned int)GetLastError()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Indicate that clipboard was opened */ fCloseClipboard = TRUE; /* Check that clipboard format is available */ if (data->fUseUnicode && !IsClipboardFormatAvailable(CF_UNICODETEXT)) { static int count; /* Hack to stop acroread spamming the log */ static HWND lasthwnd; /* I've not seen any other client get here repeatedly? */ if (hwnd != lasthwnd) count = 0; count++; if (count < 6) ErrorF("winClipboardFlushXEvents - CF_UNICODETEXT is not " "available from Win32 clipboard. Aborting %d.\n", count); lasthwnd = hwnd; /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } else if (!data->fUseUnicode && !IsClipboardFormatAvailable(CF_TEXT)) { ErrorF("winClipboardFlushXEvents - CF_TEXT is not " "available from Win32 clipboard. Aborting.\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Setup the string style */ if (event.xselectionrequest.target == XA_STRING) xiccesStyle = XStringStyle; #ifdef X_HAVE_UTF8_STRING else if (event.xselectionrequest.target == atomUTF8String) xiccesStyle = XUTF8StringStyle; #endif else if (event.xselectionrequest.target == atomCompoundText) xiccesStyle = XCompoundTextStyle; else xiccesStyle = XStringStyle; /* Get a pointer to the clipboard text, in desired format */ if (data->fUseUnicode) { /* Retrieve clipboard data */ hGlobal = GetClipboardData(CF_UNICODETEXT); } else { /* Retrieve clipboard data */ hGlobal = GetClipboardData(CF_TEXT); } if (!hGlobal) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "GetClipboardData () failed: %08x\n", (unsigned int)GetLastError()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } pszGlobalData = (char *) GlobalLock(hGlobal); /* Convert the Unicode string to UTF8 (MBCS) */ if (data->fUseUnicode) { int iConvertDataLen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) pszGlobalData, -1, NULL, 0, NULL, NULL); /* NOTE: iConvertDataLen includes space for null terminator */ pszConvertData = malloc(iConvertDataLen); WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) pszGlobalData, -1, pszConvertData, iConvertDataLen, NULL, NULL); } else { pszConvertData = strdup(pszGlobalData); } /* Convert DOS string to UNIX string */ winClipboardDOStoUNIX(pszConvertData, strlen(pszConvertData)); /* Setup our text list */ pszTextList[0] = pszConvertData; pszTextList[1] = NULL; /* Initialize the text property */ xtpText.value = NULL; xtpText.nitems = 0; /* Create the text property from the text list */ if (data->fUseUnicode) { #ifdef X_HAVE_UTF8_STRING iReturn = Xutf8TextListToTextProperty(pDisplay, pszTextList, 1, xiccesStyle, &xtpText); #endif } else { iReturn = XmbTextListToTextProperty(pDisplay, pszTextList, 1, xiccesStyle, &xtpText); } if (iReturn == XNoMemory || iReturn == XLocaleNotSupported) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "X*TextListToTextProperty failed: %d\n", iReturn); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Free the converted string */ free(pszConvertData); pszConvertData = NULL; /* Copy the clipboard text to the requesting window */ iReturn = XChangeProperty(pDisplay, event.xselectionrequest.requestor, event.xselectionrequest.property, event.xselectionrequest.target, 8, PropModeReplace, xtpText.value, xtpText.nitems); if (iReturn == BadAlloc || iReturn == BadAtom || iReturn == BadMatch || iReturn == BadValue || iReturn == BadWindow) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "XChangeProperty failed: %d\n", iReturn); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } /* Release the clipboard data */ GlobalUnlock(hGlobal); pszGlobalData = NULL; fCloseClipboard = FALSE; CloseClipboard(); /* Clean up */ XFree(xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; /* Setup selection notify event */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = event.xselectionrequest.property; eventSelection.time = event.xselectionrequest.time; /* Notify the requesting window that the operation has completed */ iReturn = XSendEvent(pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { ErrorF("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionRequest_Done; } winClipboardFlushXEvents_SelectionRequest_Done: /* Free allocated resources */ if (xtpText.value) { XFree(xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; } free(pszConvertData); if (hGlobal && pszGlobalData) GlobalUnlock(hGlobal); /* * Send a SelectionNotify event to the requesting * client when we abort. */ if (fAbort) { /* Setup selection notify event */ eventSelection.type = SelectionNotify; eventSelection.send_event = True; eventSelection.display = pDisplay; eventSelection.requestor = event.xselectionrequest.requestor; eventSelection.selection = event.xselectionrequest.selection; eventSelection.target = event.xselectionrequest.target; eventSelection.property = None; eventSelection.time = event.xselectionrequest.time; /* Notify the requesting window that the operation is complete */ iReturn = XSendEvent(pDisplay, eventSelection.requestor, False, 0L, (XEvent *) &eventSelection); if (iReturn == BadValue || iReturn == BadWindow) { /* * Should not be a problem if XSendEvent fails because * the client may simply have exited. */ ErrorF("winClipboardFlushXEvents - SelectionRequest - " "XSendEvent () failed for abort event.\n"); } } /* Close clipboard if it was opened */ if (fCloseClipboard) { fCloseClipboard = FALSE; CloseClipboard(); } break; /* * SelectionNotify */ case SelectionNotify: winDebug("winClipboardFlushXEvents - SelectionNotify\n"); { char *pszAtomName; pszAtomName = XGetAtomName(pDisplay, event.xselection.selection); winDebug ("winClipboardFlushXEvents - SelectionNotify - ATOM: %s\n", pszAtomName); XFree(pszAtomName); } /* SelectionNotify with property of None indicates either: (i) Generated by the X server if no owner for the specified selection exists (perhaps it's disappeared on us mid-transaction), or (ii) Sent by the selection owner when the requested selection conversion could not be performed or server errors prevented the conversion data being returned */ if (event.xselection.property == None) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "Conversion to format %ld refused.\n", event.xselection.target); return WIN_XEVENTS_FAILED; } if (event.xselection.target == atomTargets) { return winClipboardSelectionNotifyTargets(hwnd, iWindow, pDisplay, data, atoms); } /* Retrieve the selection data and delete the property */ iReturn = XGetWindowProperty(pDisplay, iWindow, atomLocalProperty, 0, INT_MAX, True, AnyPropertyType, &xtpText.encoding, &xtpText.format, &xtpText.nitems, &ulReturnBytesLeft, &xtpText.value); if (iReturn != Success) { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "XGetWindowProperty () failed, aborting: %d\n", iReturn); goto winClipboardFlushXEvents_SelectionNotify_Done; } { char *pszAtomName = NULL; winDebug("SelectionNotify - returned data %lu left %lu\n", xtpText.nitems, ulReturnBytesLeft); pszAtomName = XGetAtomName(pDisplay, xtpText.encoding); winDebug("Notify atom name %s\n", pszAtomName); XFree(pszAtomName); pszAtomName = NULL; } if (data->fUseUnicode) { #ifdef X_HAVE_UTF8_STRING /* Convert the text property to a text list */ iReturn = Xutf8TextPropertyToTextList(pDisplay, &xtpText, &ppszTextList, &iCount); #endif } else { iReturn = XmbTextPropertyToTextList(pDisplay, &xtpText, &ppszTextList, &iCount); } if (iReturn == Success || iReturn > 0) { /* Conversion succeeded or some unconvertible characters */ if (ppszTextList != NULL) { int i; int iReturnDataLen = 0; for (i = 0; i < iCount; i++) { iReturnDataLen += strlen(ppszTextList[i]); } pszReturnData = malloc(iReturnDataLen + 1); pszReturnData[0] = '\0'; for (i = 0; i < iCount; i++) { strcat(pszReturnData, ppszTextList[i]); } } else { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "X*TextPropertyToTextList list_return is NULL.\n"); pszReturnData = malloc(1); pszReturnData[0] = '\0'; } } else { ErrorF("winClipboardFlushXEvents - SelectionNotify - " "X*TextPropertyToTextList returned: "); switch (iReturn) { case XNoMemory: ErrorF("XNoMemory\n"); break; case XLocaleNotSupported: ErrorF("XLocaleNotSupported\n"); break; case XConverterNotFound: ErrorF("XConverterNotFound\n"); break; default: ErrorF("%d\n", iReturn); break; } pszReturnData = malloc(1); pszReturnData[0] = '\0'; } /* Free the data returned from XGetWindowProperty */ if (ppszTextList) XFreeStringList(ppszTextList); ppszTextList = NULL; XFree(xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; /* Convert the X clipboard string to DOS format */ winClipboardUNIXtoDOS(&pszReturnData, strlen(pszReturnData)); if (data->fUseUnicode) { /* Find out how much space needed to convert MBCS to Unicode */ int iUnicodeLen = MultiByteToWideChar(CP_UTF8, 0, pszReturnData, -1, NULL, 0); /* NOTE: iUnicodeLen includes space for null terminator */ pwszUnicodeStr = malloc(sizeof(wchar_t) * iUnicodeLen); if (!pwszUnicodeStr) { ErrorF("winClipboardFlushXEvents - SelectionNotify " "malloc failed for pwszUnicodeStr, aborting.\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Do the actual conversion */ MultiByteToWideChar(CP_UTF8, 0, pszReturnData, -1, pwszUnicodeStr, iUnicodeLen); /* Allocate global memory for the X clipboard data */ hGlobal = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * iUnicodeLen); } else { int iConvertDataLen = 0; pszConvertData = strdup(pszReturnData); iConvertDataLen = strlen(pszConvertData) + 1; /* Allocate global memory for the X clipboard data */ hGlobal = GlobalAlloc(GMEM_MOVEABLE, iConvertDataLen); } free(pszReturnData); /* Check that global memory was allocated */ if (!hGlobal) { ErrorF("winClipboardFlushXEvents - SelectionNotify " "GlobalAlloc failed, aborting: %08x\n", (unsigned int)GetLastError()); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Obtain a pointer to the global memory */ pszGlobalData = GlobalLock(hGlobal); if (pszGlobalData == NULL) { ErrorF("winClipboardFlushXEvents - Could not lock global " "memory for clipboard transfer\n"); /* Abort */ fAbort = TRUE; goto winClipboardFlushXEvents_SelectionNotify_Done; } /* Copy the returned string into the global memory */ if (data->fUseUnicode) { wcscpy((wchar_t *)pszGlobalData, pwszUnicodeStr); free(pwszUnicodeStr); pwszUnicodeStr = NULL; } else { strcpy(pszGlobalData, pszConvertData); free(pszConvertData); pszConvertData = NULL; } /* Release the pointer to the global memory */ GlobalUnlock(hGlobal); pszGlobalData = NULL; /* Push the selection data to the Windows clipboard */ if (data->fUseUnicode) SetClipboardData(CF_UNICODETEXT, hGlobal); else SetClipboardData(CF_TEXT, hGlobal); /* Flag that SetClipboardData has been called */ fSetClipboardData = FALSE; /* * NOTE: Do not try to free pszGlobalData, it is owned by * Windows after the call to SetClipboardData (). */ winClipboardFlushXEvents_SelectionNotify_Done: /* Free allocated resources */ if (ppszTextList) XFreeStringList(ppszTextList); if (xtpText.value) { XFree(xtpText.value); xtpText.value = NULL; xtpText.nitems = 0; } free(pszConvertData); free(pwszUnicodeStr); if (hGlobal && pszGlobalData) GlobalUnlock(hGlobal); if (fSetClipboardData) { SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); } return WIN_XEVENTS_NOTIFY_DATA; case SelectionClear: winDebug("SelectionClear - doing nothing\n"); break; case PropertyNotify: break; case MappingNotify: break; default: if (event.type == XFixesSetSelectionOwnerNotify + xfixes_event_base) { XFixesSelectionNotifyEvent *e = (XFixesSelectionNotifyEvent *) & event; winDebug("winClipboardFlushXEvents - XFixesSetSelectionOwnerNotify\n"); /* Save selection owners for monitored selections, ignore other selections */ if ((e->selection == XA_PRIMARY) && fPrimarySelection) { MonitorSelection(e, CLIP_OWN_PRIMARY); } else if (e->selection == atomClipboard) { MonitorSelection(e, CLIP_OWN_CLIPBOARD); } else break; /* Selection is being disowned */ if (e->owner == None) { winDebug ("winClipboardFlushXEvents - No window, returning.\n"); break; } /* XXX: there are all kinds of wacky edge cases we might need here: - we own windows clipboard, but neither PRIMARY nor CLIPBOARD have an owner, so we should disown it? - root window is taking ownership? */ /* If we are the owner of the most recently owned selection, don't go all recursive :) */ if ((lastOwnedSelectionIndex != CLIP_OWN_NONE) && (s_iOwners[lastOwnedSelectionIndex] == iWindow)) { winDebug("winClipboardFlushXEvents - Ownership changed to us, aborting.\n"); break; } /* Close clipboard if we have it open already (possible? correct??) */ if (GetOpenClipboardWindow() == hwnd) { CloseClipboard(); } /* Access the Windows clipboard */ if (!OpenClipboard(hwnd)) { ErrorF("winClipboardFlushXEvents - OpenClipboard () failed: %08x\n", (int) GetLastError()); break; } /* Take ownership of the Windows clipboard */ if (!EmptyClipboard()) { ErrorF("winClipboardFlushXEvents - EmptyClipboard () failed: %08x\n", (int) GetLastError()); break; } /* Advertise regular text and unicode */ SetClipboardData(CF_UNICODETEXT, NULL); SetClipboardData(CF_TEXT, NULL); /* Release the clipboard */ if (!CloseClipboard()) { ErrorF("winClipboardFlushXEvents - CloseClipboard () failed: %08x\n", (int) GetLastError()); break; } } /* XFixesSelectionWindowDestroyNotifyMask */ /* XFixesSelectionClientCloseNotifyMask */ else { ErrorF("winClipboardFlushXEvents - unexpected event type %d\n", event.type); } break; } } return WIN_XEVENTS_SUCCESS; }
/** * Retrieves the data from a certain source Atom using a specific * format. * * \param source The currently active clipboard Atom to get the data from. * \param format The format of the data to get. * \param length Out parameter that contains the length of the returned * buffer. * \return The requested content or NULL in case no content exists or an * error occured. */ static int _get_data_as (Atom source, Atom format, char **data, unsigned int *size) { Window owner; time_t start; Atom sel_type; int sel_format; unsigned long nbytes, overflow; *size = 0; unsigned char *src; unsigned long offset = 0; unsigned long chunk = 0; int step = 1; XEvent ev; Time timestamp; /* If we are the owner, simply return the clip buffer, if it matches * the request type. */ if (!scrap_lost_x11 ()) { char *fmt; fmt = _atom_to_string (format); /* TODO */ free (fmt); return 1; } Lock_Display (); /* Find a selection owner. */ owner = _get_scrap_owner (&source); if (owner == None) { Unlock_Display (); SDL_SetError ("no clipboard owner found"); return 0; } timestamp = (source == XA_PRIMARY) ? _selectiontime : _cliptime; /* Copy and convert the selection into our SDL_SELECTION atom of the * window. * Flush afterwards, so we have an immediate effect and do not receive * the old buffer anymore. */ XConvertSelection (_sdldisplay, source, format, _atom_SDL, _sdlwindow, timestamp); XSync (_sdldisplay, False); /* Let's wait for the SelectionNotify event from the callee and * react upon it as soon as it is received. */ for (start = time (0);;) { if (XCheckTypedWindowEvent (_sdldisplay, _sdlwindow, SelectionNotify, &ev)) break; if (time (0) - start >= 5) { /* Timeout, damn. */ Unlock_Display (); SDL_SetError ("timeout on retrieving the clipboard data"); return 0; } } /* Get any property type and check the sel_type afterwards to decide * what to do. */ if (XGetWindowProperty (_sdldisplay, ev.xselection.requestor, _atom_SDL, 0, 0, True, AnyPropertyType, &sel_type, &sel_format, &nbytes, &overflow, &src) != Success) { XFree (src); Unlock_Display (); SDL_SetError ("could not receive clipboard buffer"); return 0; } /* In case we requested a SCRAP_TEXT, any property type of * XA_STRING, XA_COMPOUND_TEXT, UTF8_STRING and TEXT is valid. */ if (format == _atom_MIME_PLAIN && (sel_type != _atom_UTF8 && sel_type != _atom_TEXT && sel_type != _atom_COMPOUND && sel_type != XA_STRING)) { /* No matching text type found. Return nothing then. */ XFree (src); Unlock_Display (); SDL_SetError ("text format not found"); return 0; } /* Anything is fine, so copy the buffer and return it. */ switch (sel_format) { case 16: step = sizeof (short) / 2; break; case 32: step = sizeof (long) / 4; break; case 8: default: step = sizeof (char); *size = overflow; /* 8 bit size is already correctly set in nbytes.*/ break; } /* X11 guarantees NULL termination, add an extra byte. */ *size = step * overflow; *data = malloc (*size + 1); if (*data) { unsigned long boffset = 0; chunk = MAX_CHUNK_SIZE(_sdldisplay); memset (*data, 0, (size_t) (*size + 1)); /* Read as long as there is data. */ while (overflow) { if (XGetWindowProperty (_sdldisplay, ev.xselection.requestor, _atom_SDL, offset, chunk, True, AnyPropertyType, &sel_type, &sel_format, &nbytes, &overflow, &src) != Success) { break; } offset += nbytes / (32 / sel_format); nbytes *= step * sel_format / 8; memcpy ((*data) + boffset, src, nbytes); boffset += nbytes; XFree (src); } } else { /* ENOMEM */ SDL_SetError ("could not allocate memory"); return 0; } /* In case we've got a COMPOUND_TEXT, convert it to the current * multibyte locale. */ if (sel_type == _atom_COMPOUND && sel_format == 8) { char **list = NULL; int count, status = 0; XTextProperty p; p.encoding = sel_type; p.format = sel_format; p.nitems = nbytes; p.value = (unsigned char*)(*data); status = XmbTextPropertyToTextList (_sdldisplay, &p, &list, &count); if (status == XLocaleNotSupported || status == XConverterNotFound) { free (*data); SDL_SetError ("current locale is not supported for conversion."); return 0; } else if (status == XNoMemory) { free (*data); SDL_SetError ("could not allocate memory"); return 0; } else if (status == Success) { if (count && list) { int i = 0; int ioffset = 0; char *tmp; free (*data); *data = NULL; for (i = 0; i < count; i++) { *size = strlen (list[i]); tmp = *data; *data = realloc (*data, (*size) + 1); if (!(*data)) { free (tmp); SDL_SetError ("could not allocate memory"); return 0; } ioffset += *size; memcpy (*data, list[i], *size); memset ((*data) + ioffset, '\n', 1); } memset ((*data) + ioffset, 0, 1); } } if (list) XFreeStringList (list); } Unlock_Display (); return 1; }
/******************************************************************** * * Setup a child service record per the selection request. */ void mgr_initialize( XEvent *report, XpPdmServiceRec *rec ) { Display *testdpy; char buf[1024]; Display *selection_display; Window requestor; Atom prop_atom; unsigned long tafter; XTextProperty text_prop; char **list; int list_cnt; /* * Grab the PDM_CLIENT_PROP from which all the juicy * information is retrieved. */ selection_display = report->xselectionrequest.display; requestor = report->xselectionrequest.requestor; prop_atom = report->xselectionrequest.property; if ( XGetWindowProperty( selection_display, requestor, prop_atom, 0, 100000, True, AnyPropertyType, &text_prop.encoding, &text_prop.format, &text_prop.nitems, &tafter, &text_prop.value ) != Success ) { /* * Error */ rec->pdm_exec_errorcode = g.pdm_start_error; sprintf( buf, PDMD_MSG_5, g.prog_name ); rec->pdm_exec_errormessage = xpstrdup( buf ); return; } if ( text_prop.format != 8 ) { /* * Error */ rec->pdm_exec_errorcode = g.pdm_start_error; sprintf( buf, PDMD_MSG_6, g.prog_name ); rec->pdm_exec_errormessage = xpstrdup( buf ); return; } if ( XmbTextPropertyToTextList( selection_display, &text_prop, &list, &list_cnt ) < 0 ) { /* * Error */ rec->pdm_exec_errorcode = g.pdm_start_error; sprintf( buf, PDMD_MSG_7, g.prog_name ); rec->pdm_exec_errormessage = xpstrdup( buf ); return; } /* * Fill in the PDM_MANAGER portion of the client record. */ rec->video_display_str = xpstrdup( list[0] ); rec->video_window = strtol(list[1], (char **)NULL, 16); rec->print_display_str = xpstrdup( list[2] ); rec->print_window = strtol(list[3], (char **)NULL, 16); #if 0 && defined(PRINTING_SUPPORTED) rec->print_context = strtol(list[4], (char **)NULL, 16); #endif /* PRINTING_SUPPORTED */ rec->locale_hint = xpstrdup( list[5] ); XFreeStringList( list ); rec->selection_display = selection_display; rec->requestor = requestor; rec->prop_atom = prop_atom; rec->selection = report->xselectionrequest.selection; rec->time = report->xselectionrequest.time; rec->mgr_flag = True; /* mgr portion of rec now valid */ /* * Optimization. The only live display connection, for which we * need to trap XIO errors, is "selection display". For the * "video" and "print" displays, we have the display strings and * can establish connections as we need them. Since they are rarely * used, and opening them up here would create XIO liability problems * and a startup performance hit, we won't establish connections now. * * One optimization however is to see if the "print" display would * just happen to be the same at the "selection display" currently * open. */ if ( !strcmp( XDisplayString(rec->selection_display), rec->print_display_str ) ) { rec->seldpy_as_printdpy = True; } else { rec->seldpy_as_printdpy = False; #ifdef OPTIONAL_PXAUTH_PRETEST /* * Verify connectability to the Print Server. * * Note: once beyond the selection phase, all communication * will be by way of the Print Server. If we cannot * connect later, then we will have no way to deliver * EXIT_PXAUTH, EXIT_VXAUTH, EXIT_ERROR, EXIT_OK or * EXIT_CANCEL. Real bad news! * * It is better to discover now that we don't have * connection authorization for the print display since * we can still let the user know of PXAUTH problems * via the selection display currently open. * * Unfortunately, this pre-test is a performance hit in the * startup phase. */ if ( ! (testdpy = XOpenDisplay(rec->print_display_str)) ) { rec->pdm_exec_errorcode = g.pdm_start_pxauth; return; } XCloseDisplay( testdpy ); #endif /* OPTIONAL_PXAUTH_PRETEST */ } #ifdef OPTIONAL_VXAUTH_PRETEST /* * Verify connectability to the Video Server. * * It is better to discover now that we don't have * connection authorization for the video display since * we can still let the user know of VXAUTH problems * via the selection display currently open. * * Unfortunately, this pre-test is a performance hit in the * startup phase. */ if ( ! (testdpy = XOpenDisplay(rec->video_display_str)) ) { rec->pdm_exec_errorcode = g.pdm_start_vxauth; return; } XCloseDisplay( testdpy ); #endif /* OPTIONAL_VXAUTH_PRETEST */ }
Client *createclient(Window w) { extern void checkstyle(Client *c); XWindowAttributes attr; Client *c; if(w==0) return 0; if(!XFindContext(dpy, w, client_context, (XPointer*)&c)) return c; XGetWindowAttributes(dpy, w, &attr); c = (Client *)calloc(1, sizeof(Client)); c->scr = scr; c->window = w; c->parent = scr->root; c->old_bw = attr.border_width; c->next = clients; c->state = WithdrawnState; c->gravity = NorthWestGravity; c->reparenting = 0; XSelectInput(dpy, c->window, PropertyChangeMask); #ifdef USE_FONTSETS { XTextProperty prop; c->title = NULL; if(XGetWMName(dpy, c->window, &prop) && prop.value) { char **list; int n; if(XmbTextPropertyToTextList(dpy, &prop, &list, &n) >= Success) { if(n > 0) c->title = strdup(list[0]); XFreeStringList(list); } XFree(prop.value); } } #else XGetWMName(dpy, c->window, &c->title); #endif c->style = NULL; checkstyle(c); checksizehints(c); c->zoomx=0; c->zoomy=scr->bh; if(c->sizehints.width_inc) { c->zoomw=scr->width-c->sizehints.base_width-22; c->zoomw-=c->zoomw%c->sizehints.width_inc; c->zoomw+=c->sizehints.base_width; if(c->zoomw>c->sizehints.max_width) c->zoomw=c->sizehints.max_width; if(c->zoomw<c->sizehints.min_width) c->zoomw=c->sizehints.min_width; } else c->zoomw=attr.width; if(c->sizehints.height_inc) { c->zoomh=scr->height-c->sizehints.base_height-scr->bh-c->zoomy-2; c->zoomh-=c->zoomh%c->sizehints.height_inc; c->zoomh+=c->sizehints.base_height; if(c->zoomh>c->sizehints.max_height) c->zoomh=c->sizehints.max_height; if(c->zoomh<c->sizehints.min_height) c->zoomh=c->sizehints.min_height; } else c->zoomh=attr.height; XSaveContext(dpy, w, client_context, (XPointer)c); return clients = c; }