diff options
Diffstat (limited to 'hw/xwin/winclipboardthread.c')
-rw-r--r-- | hw/xwin/winclipboardthread.c | 559 |
1 files changed, 290 insertions, 269 deletions
diff --git a/hw/xwin/winclipboardthread.c b/hw/xwin/winclipboardthread.c index 181cb7203..8de7d2f25 100644 --- a/hw/xwin/winclipboardthread.c +++ b/hw/xwin/winclipboardthread.c @@ -46,400 +46,410 @@ * References to external symbols */ -extern Bool g_fUnicodeClipboard; -extern unsigned long serverGeneration; -extern Bool g_fClipboardStarted; -extern Bool g_fClipboardLaunched; -extern Bool g_fClipboard; -extern HWND g_hwndClipboard; -extern void *g_pClipboardDisplay; -extern Window g_iClipboardWindow; +extern Bool g_fUnicodeClipboard; +extern unsigned long serverGeneration; +extern Bool g_fClipboardStarted; +extern Bool g_fClipboardLaunched; +extern Bool g_fClipboard; +extern HWND g_hwndClipboard; +extern void *g_pClipboardDisplay; +extern Window g_iClipboardWindow; /* * Global variables */ -static jmp_buf g_jmpEntry; +static jmp_buf g_jmpEntry; static int clipboardRestarts = 0; static XIOErrorHandler g_winClipboardOldIOErrorHandler; static pthread_t g_winClipboardProcThread; -Bool g_fUnicodeSupport = FALSE; -Bool g_fUseUnicode = FALSE; +Bool g_fUseUnicode = FALSE; /* * Local function prototypes */ static int - winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr); +winClipboardErrorHandler (Display *pDisplay, XErrorEvent *pErr); static int - winClipboardIOErrorHandler(Display * pDisplay); +winClipboardIOErrorHandler (Display *pDisplay); + +static void +winClipboardThreadExit(void *arg); /* * Main thread function */ void * -winClipboardProc(void *pvNotUsed) +winClipboardProc (void *pvNotUsed) { - Atom atomClipboard, atomClipboardManager; - int iReturn; - HWND hwnd = NULL; - int iConnectionNumber = 0; + Atom atomClipboard, atomClipboardManager; + int iReturn; + HWND hwnd = NULL; + int iConnectionNumber = 0; #ifdef HAS_DEVWINDOWS - int fdMessageQueue = 0; + int fdMessageQueue = 0; #else - struct timeval tvTimeout; + struct timeval tvTimeout; #endif - fd_set fdsRead; - int iMaxDescriptor; - Display *pDisplay = NULL; - Window iWindow = None; - int iRetries; - Bool fUseUnicode; - char szDisplay[512]; - int iSelectError; - - ErrorF("winClipboardProc - Hello\n"); - ++clipboardRestarts; - - /* Do we have Unicode support? */ - g_fUnicodeSupport = winClipboardDetectUnicodeSupport(); - - /* Do we use Unicode clipboard? */ - fUseUnicode = g_fUnicodeClipboard && g_fUnicodeSupport; - - /* Save the Unicode support flag in a global */ - g_fUseUnicode = fUseUnicode; - - /* Allow multiple threads to access Xlib */ - if (XInitThreads() == 0) { - ErrorF("winClipboardProc - XInitThreads failed.\n"); - goto winClipboardProc_Exit; - } + fd_set fdsRead; + int iMaxDescriptor; + Display *pDisplay = NULL; + Window iWindow = None; + int iRetries; + Bool fUseUnicode; + char szDisplay[512]; + int iSelectError; - /* See if X supports the current locale */ - if (XSupportsLocale() == False) { - ErrorF("winClipboardProc - Warning: Locale not supported by X.\n"); - } + pthread_cleanup_push(&winClipboardThreadExit, NULL); + + winDebug ("winClipboardProc - Hello\n"); + ++clipboardRestarts; - /* Set error handler */ - XSetErrorHandler(winClipboardErrorHandler); - g_winClipboardProcThread = pthread_self(); + /* Do we use Unicode clipboard? */ + fUseUnicode = g_fUnicodeClipboard; + + /* Save the Unicode support flag in a global */ + g_fUseUnicode = fUseUnicode; + + /* Set error handler */ + XSetErrorHandler (winClipboardErrorHandler); + g_winClipboardProcThread = pthread_self(); g_winClipboardOldIOErrorHandler = XSetIOErrorHandler(winClipboardIOErrorHandler); - /* Set jump point for Error exits */ - iReturn = setjmp(g_jmpEntry); - - /* Check if we should continue operations */ + /* Set jump point for Error exits */ + iReturn = setjmp (g_jmpEntry); + + /* Check if we should continue operations */ if (iReturn != WIN_JMP_ERROR_IO && iReturn != WIN_JMP_OKAY) { - /* setjmp returned an unknown value, exit */ + /* setjmp returned an unknown value, exit */ ErrorF("winClipboardProc - setjmp returned: %d exiting\n", iReturn); - goto winClipboardProc_Exit; + goto winClipboardProc_Exit; } - else if (iReturn == WIN_JMP_ERROR_IO) { - /* TODO: Cleanup the Win32 window and free any allocated memory */ - ErrorF("winClipboardProc - setjmp returned for IO Error Handler.\n"); - pthread_exit(NULL); + else if (iReturn == WIN_JMP_ERROR_IO) + { + /* TODO: cleanup and free any allocated memory */ + ErrorF("winClipboardProc - setjmp returned for IO Error Handler\n"); + goto winClipboardProc_Done; } - /* Use our generated cookie for authentication */ - winSetAuthorization(); + /* Use our generated cookie for authentication */ + winSetAuthorization(); - /* Initialize retry count */ - iRetries = 0; + /* Initialize retry count */ + iRetries = 0; - /* Setup the display connection string x */ - /* - * NOTE: Always connect to screen 0 since we require that screen - * numbers start at 0 and increase without gaps. We only need - * to connect to one screen on the display to get events - * for all screens on the display. That is why there is only - * one clipboard client thread. - */ - snprintf(szDisplay, 512, "127.0.0.1:%s.0", display); + /* Setup the display connection string x */ + /* + * NOTE: Always connect to screen 0 since we require that screen + * numbers start at 0 and increase without gaps. We only need + * to connect to one screen on the display to get events + * for all screens on the display. That is why there is only + * one clipboard client thread. + */ + winGetDisplayName(szDisplay, 0); - /* Print the display connection string */ - ErrorF("winClipboardProc - DISPLAY=%s\n", szDisplay); + /* Print the display connection string */ + ErrorF ("winClipboardProc - DISPLAY=%s\n", szDisplay); - /* Open the X display */ + /* Open the X display */ do { - pDisplay = XOpenDisplay(szDisplay); + pDisplay = XOpenDisplay (szDisplay); if (pDisplay == NULL) { - ErrorF("winClipboardProc - Could not open display, " + ErrorF ("winClipboardProc - Could not open display, " "try: %d, sleeping: %d\n", iRetries + 1, WIN_CONNECT_DELAY); - ++iRetries; - sleep(WIN_CONNECT_DELAY); - continue; - } - else - break; + ++iRetries; + sleep (WIN_CONNECT_DELAY); + continue; + } + else + break; } - while (pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); + while (pDisplay == NULL && iRetries < WIN_CONNECT_RETRIES); - /* Make sure that the display opened */ + /* Make sure that the display opened */ if (pDisplay == NULL) { - ErrorF("winClipboardProc - Failed opening the display, giving up\n"); - goto winClipboardProc_Done; + ErrorF ("winClipboardProc - Failed opening the display, giving up\n"); + goto winClipboardProc_Done; } - /* Save the display in the screen privates */ - g_pClipboardDisplay = pDisplay; + /* Save the display in a global used by the wndproc */ + g_pClipboardDisplay = pDisplay; - ErrorF("winClipboardProc - XOpenDisplay () returned and " - "successfully opened the display.\n"); + ErrorF ("winClipboardProc - XOpenDisplay () returned and " + "successfully opened the display.\n"); - /* Get our connection number */ - iConnectionNumber = ConnectionNumber(pDisplay); + /* Get our connection number */ + iConnectionNumber = ConnectionNumber (pDisplay); #ifdef HAS_DEVWINDOWS - /* Open a file descriptor for the windows message queue */ - fdMessageQueue = open(WIN_MSG_QUEUE_FNAME, O_RDONLY); + /* Open a file descriptor for the windows message queue */ + fdMessageQueue = open (WIN_MSG_QUEUE_FNAME, O_RDONLY); if (fdMessageQueue == -1) { - ErrorF("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME); - goto winClipboardProc_Done; + ErrorF ("winClipboardProc - Failed opening %s\n", WIN_MSG_QUEUE_FNAME); + goto winClipboardProc_Done; } - /* Find max of our file descriptors */ - iMaxDescriptor = max(fdMessageQueue, iConnectionNumber) + 1; + /* Find max of our file descriptors */ + iMaxDescriptor = max (fdMessageQueue, iConnectionNumber) + 1; #else - iMaxDescriptor = iConnectionNumber + 1; + iMaxDescriptor = iConnectionNumber + 1; #endif - /* Create atoms */ - atomClipboard = XInternAtom(pDisplay, "CLIPBOARD", False); - atomClipboardManager = XInternAtom(pDisplay, "CLIPBOARD_MANAGER", False); - - /* Create a messaging window */ - iWindow = XCreateSimpleWindow(pDisplay, - DefaultRootWindow(pDisplay), - 1, 1, - 500, 500, - 0, - BlackPixel(pDisplay, 0), - BlackPixel(pDisplay, 0)); + /* Create atoms */ + atomClipboard = XInternAtom (pDisplay, "CLIPBOARD", False); + atomClipboardManager = XInternAtom (pDisplay, "CLIPBOARD_MANAGER", False); + + /* Create a messaging window */ + iWindow = XCreateSimpleWindow (pDisplay, + DefaultRootWindow (pDisplay), + 1, 1, + 500, 500, + 0, + BlackPixel (pDisplay, 0), + BlackPixel (pDisplay, 0)); if (iWindow == 0) { - ErrorF("winClipboardProc - Could not create an X window.\n"); - goto winClipboardProc_Done; + ErrorF ("winClipboardProc - Could not create an X window.\n"); + goto winClipboardProc_Done; } - XStoreName(pDisplay, iWindow, "xwinclip"); + XStoreName(pDisplay, iWindow, "xwinclip"); - /* Select event types to watch */ + /* Select event types to watch */ if (XSelectInput(pDisplay, iWindow, PropertyChangeMask) == BadWindow) - ErrorF("winClipboardProc - XSelectInput generated BadWindow " - "on messaging window\n"); - - /* Save the window in the screen privates */ - g_iClipboardWindow = iWindow; + ErrorF ("winClipboardProc - XSelectInput generated BadWindow " + "on messaging window\n"); - /* Create Windows messaging window */ - hwnd = winClipboardCreateMessagingWindow(); + /* Save the window in the screen privates */ + g_iClipboardWindow = iWindow; - /* Save copy of HWND in screen privates */ - g_hwndClipboard = hwnd; + /* Create Windows messaging window */ + hwnd = winClipboardCreateMessagingWindow (); + + /* Save copy of HWND in screen privates */ + g_hwndClipboard = hwnd; - /* Assert ownership of selections if Win32 clipboard is owned */ + /* Assert ownership of selections if Win32 clipboard is owned */ if (NULL != GetClipboardOwner()) { - /* PRIMARY */ - iReturn = XSetSelectionOwner(pDisplay, XA_PRIMARY, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow || + /* PRIMARY */ + iReturn = XSetSelectionOwner (pDisplay, XA_PRIMARY, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || XGetSelectionOwner(pDisplay, XA_PRIMARY) != iWindow) { - ErrorF("winClipboardProc - Could not set PRIMARY owner\n"); - goto winClipboardProc_Done; - } - - /* CLIPBOARD */ - iReturn = XSetSelectionOwner(pDisplay, atomClipboard, - iWindow, CurrentTime); - if (iReturn == BadAtom || iReturn == BadWindow || + ErrorF ("winClipboardProc - Could not set PRIMARY owner\n"); + goto winClipboardProc_Done; + } + + /* CLIPBOARD */ + iReturn = XSetSelectionOwner (pDisplay, atomClipboard, + iWindow, CurrentTime); + if (iReturn == BadAtom || iReturn == BadWindow || XGetSelectionOwner(pDisplay, atomClipboard) != iWindow) { - ErrorF("winClipboardProc - Could not set CLIPBOARD owner\n"); - goto winClipboardProc_Done; - } + ErrorF ("winClipboardProc - Could not set CLIPBOARD owner\n"); + goto winClipboardProc_Done; + } } - /* Pre-flush X events */ - /* - * NOTE: Apparently you'll freeze if you don't do this, - * because there may be events in local data structures - * already. - */ + /* Pre-flush X events */ + /* + * NOTE: Apparently you'll freeze if you don't do this, + * because there may be events in local data structures + * already. + */ winClipboardFlushXEvents(hwnd, iWindow, pDisplay, fUseUnicode); - /* Pre-flush Windows messages */ - if (!winClipboardFlushWindowsMessageQueue(hwnd)) - return 0; + /* Pre-flush Windows messages */ + if (!winClipboardFlushWindowsMessageQueue (hwnd)) + { + ErrorF ("winClipboardProc - winClipboardFlushWindowsMessageQueue failed\n"); + pthread_exit (NULL); + } - /* Signal that the clipboard client has started */ - g_fClipboardStarted = TRUE; + /* Signal that the clipboard client has started */ + g_fClipboardStarted = TRUE; - /* Loop for X events */ + /* Loop for X events */ while (1) { - /* Setup the file descriptor set */ - /* - * NOTE: You have to do this before every call to select - * because select modifies the mask to indicate - * which descriptors are ready. - */ - FD_ZERO(&fdsRead); - FD_SET(iConnectionNumber, &fdsRead); + /* Setup the file descriptor set */ + /* + * NOTE: You have to do this before every call to select + * because select modifies the mask to indicate + * which descriptors are ready. + */ + FD_ZERO (&fdsRead); + FD_SET (iConnectionNumber, &fdsRead); #ifdef HAS_DEVWINDOWS - FD_SET(fdMessageQueue, &fdsRead); + FD_SET (fdMessageQueue, &fdsRead); #else - tvTimeout.tv_sec = 0; - tvTimeout.tv_usec = 100; + tvTimeout.tv_sec = 0; + tvTimeout.tv_usec = 100; #endif - /* Wait for a Windows event or an X event */ - iReturn = select(iMaxDescriptor, /* Highest fds number */ - &fdsRead, /* Read mask */ - NULL, /* No write mask */ - NULL, /* No exception mask */ + winDebug ("winClipboardProc - Waiting in select\n"); + + /* Wait for a Windows event or an X event */ + iReturn = select (iMaxDescriptor, /* Highest fds number */ + &fdsRead, /* Read mask */ + NULL, /* No write mask */ + NULL, /* No exception mask */ #ifdef HAS_DEVWINDOWS - NULL /* No timeout */ + NULL /* No timeout */ #else - &tvTimeout /* Set timeout */ + &tvTimeout /* Set timeout */ #endif - ); + ); #ifndef HAS_WINSOCK - iSelectError = errno; + iSelectError = errno; #else - iSelectError = WSAGetLastError(); + iSelectError = WSAGetLastError(); #endif if (iReturn < 0) { #ifndef HAS_WINSOCK - if (iSelectError == EINTR) + if (iSelectError == EINTR) #else - if (iSelectError == WSAEINTR) + if (iSelectError == WSAEINTR) #endif - continue; - - ErrorF("winClipboardProc - Call to select () failed: %d. " - "Bailing.\n", iReturn); - break; - } - - /* Branch on which descriptor became active */ - if (FD_ISSET(iConnectionNumber, &fdsRead)) { - /* Process X events */ - /* Exit when we see that server is shutting down */ - iReturn = winClipboardFlushXEvents(hwnd, + continue; + + ErrorF ("winClipboardProc - Call to select () failed: %d. " + "Bailing.\n", iReturn); + break; + } + + winDebug ("winClipboardProc - select returned %d\n", iReturn); + + /* Branch on which descriptor became active */ + if (FD_ISSET (iConnectionNumber, &fdsRead)) + { + winDebug ("winClipboardProc - X connection ready, pumping X event queue\n"); + + /* Process X events */ + /* Exit when we see that server is shutting down */ + iReturn = winClipboardFlushXEvents (hwnd, iWindow, pDisplay, fUseUnicode); if (WIN_XEVENTS_SHUTDOWN == iReturn) { - ErrorF("winClipboardProc - winClipboardFlushXEvents " - "trapped shutdown event, exiting main loop.\n"); - break; - } - } + ErrorF ("winClipboardProc - winClipboardFlushXEvents " + "trapped shutdown event, exiting main loop.\n"); + break; + } + } #ifdef HAS_DEVWINDOWS - /* Check for Windows event ready */ - if (FD_ISSET(fdMessageQueue, &fdsRead)) + /* Check for Windows event ready */ + if (FD_ISSET (fdMessageQueue, &fdsRead)) #else - if (1) + if (1) #endif - { - /* Process Windows messages */ + { + winDebug ("winClipboardProc - /dev/windows ready, pumping Windows message queue\n"); + + /* Process Windows messages */ if (!winClipboardFlushWindowsMessageQueue(hwnd)) { - ErrorF("winClipboardProc - " - "winClipboardFlushWindowsMessageQueue trapped " - "WM_QUIT message, exiting main loop.\n"); - break; - } + ErrorF ("winClipboardProc - " + "winClipboardFlushWindowsMessageQueue trapped " + "WM_QUIT message, exiting main loop.\n"); + break; + } + } + + if (!(FD_ISSET(iConnectionNumber, &fdsRead)) && !(FD_ISSET(fdMessageQueue, &fdsRead))) + { + winDebug ("winClipboardProc - Spurious wake\n"); } } - winClipboardProc_Exit: - /* disable the clipboard, which means the thread will die */ - g_fClipboard = FALSE; +winClipboardProc_Exit: + /* disable the clipboard, which means the thread will die */ + g_fClipboard = FALSE; - winClipboardProc_Done: - /* Close our Windows window */ +winClipboardProc_Done: + /* Close our Windows window */ if (g_hwndClipboard) { - /* Destroy the Window window (hwnd) */ - winDebug("winClipboardProc - Destroy Windows window\n"); - PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0); - winClipboardFlushWindowsMessageQueue(g_hwndClipboard); + /* Destroy the Window window (hwnd) */ + winDebug("winClipboardProc - Destroy Windows window\n"); + PostMessage(g_hwndClipboard, WM_DESTROY, 0, 0); + winClipboardFlushWindowsMessageQueue(g_hwndClipboard); } - /* Close our X window */ + /* Close our X window */ if (pDisplay && iWindow) { - iReturn = XDestroyWindow(pDisplay, iWindow); - if (iReturn == BadWindow) - ErrorF("winClipboardProc - XDestroyWindow returned BadWindow.\n"); - else - ErrorF("winClipboardProc - XDestroyWindow succeeded.\n"); + iReturn = XDestroyWindow (pDisplay, iWindow); + if (iReturn == BadWindow) + ErrorF ("winClipboardProc - XDestroyWindow returned BadWindow.\n"); + else + ErrorF ("winClipboardProc - XDestroyWindow succeeded.\n"); } #ifdef HAS_DEVWINDOWS - /* Close our Win32 message handle */ - if (fdMessageQueue) - close(fdMessageQueue); + /* Close our Win32 message handle */ + if (fdMessageQueue) + close (fdMessageQueue); #endif #if 0 - /* - * FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The - * XSync and XSelectInput calls did not help. - */ + /* + * FIXME: XCloseDisplay hangs if we call it, as of 2004/03/26. The + * XSync and XSelectInput calls did not help. + */ - /* Discard any remaining events */ - XSync(pDisplay, TRUE); + /* Discard any remaining events */ + XSync (pDisplay, TRUE); - /* Select event types to watch */ + /* Select event types to watch */ XSelectInput(pDisplay, DefaultRootWindow(pDisplay), None); - /* Close our X display */ + /* Close our X display */ if (pDisplay) { - XCloseDisplay(pDisplay); + XCloseDisplay (pDisplay); } #endif - /* global clipboard variable reset */ - g_fClipboardLaunched = FALSE; - g_fClipboardStarted = FALSE; - g_iClipboardWindow = None; - g_pClipboardDisplay = NULL; - g_hwndClipboard = NULL; + /* global clipboard variable reset */ + g_fClipboardLaunched = FALSE; + g_fClipboardStarted = FALSE; + g_iClipboardWindow = None; + g_pClipboardDisplay = NULL; + g_hwndClipboard = NULL; - /* checking if we need to restart */ + /* checking if we need to restart */ if (clipboardRestarts >= WIN_CLIPBOARD_RETRIES) { - /* terminates clipboard thread but the main server still lives */ + /* terminates clipboard thread but the main server still lives */ ErrorF ("winClipboardProc - the clipboard thread has restarted %d times and seems to be unstable, disabling clipboard integration\n", clipboardRestarts); - g_fClipboard = FALSE; - return; + g_fClipboard = FALSE; + return; } if (g_fClipboard) { - sleep(WIN_CLIPBOARD_DELAY); - ErrorF("winClipboardProc - trying to restart clipboard thread \n"); - /* Create the clipboard client thread */ + sleep(WIN_CLIPBOARD_DELAY); + ErrorF("winClipboardProc - trying to restart clipboard thread \n"); + /* Create the clipboard client thread */ if (!winInitClipboard()) { - ErrorF("winClipboardProc - winClipboardInit failed.\n"); - return; + ErrorF ("winClipboardProc - winClipboardInit failed.\n"); + return; } - winDebug("winClipboardProc - winInitClipboard returned.\n"); - /* Flag that clipboard client has been launched */ - g_fClipboardLaunched = TRUE; + winDebug ("winClipboardProc - winInitClipboard returned.\n"); + /* Flag that clipboard client has been launched */ + g_fClipboardLaunched = TRUE; } else { - ErrorF("winClipboardProc - Clipboard disabled - Exit from server \n"); - /* clipboard thread has exited, stop server as well */ - kill(getpid(), SIGTERM); + ErrorF ("winClipboardProc - Clipboard disabled - Exit from server \n"); + /* clipboard thread has exited, stop server as well */ + kill(getpid(), SIGTERM); } - return NULL; + pthread_cleanup_pop(0); + + return NULL; } /* @@ -447,15 +457,15 @@ winClipboardProc(void *pvNotUsed) */ static int -winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr) +winClipboardErrorHandler (Display *pDisplay, XErrorEvent *pErr) { - char pszErrorMsg[100]; - + char pszErrorMsg[100]; + XGetErrorText(pDisplay, pErr->error_code, pszErrorMsg, sizeof(pszErrorMsg)); - ErrorF("winClipboardErrorHandler - ERROR: \n\t%s\n" - "\tSerial: %lu, Request Code: %d, Minor Code: %d\n", + ErrorF ("winClipboardErrorHandler - ERROR: \n\t%s\n" + "\tSerial: %lu, Request Code: %d, Minor Code: %d\n", pszErrorMsg, pErr->serial, pErr->request_code, pErr->minor_code); - return 0; + return 0; } /* @@ -463,17 +473,28 @@ winClipboardErrorHandler(Display * pDisplay, XErrorEvent * pErr) */ static int -winClipboardIOErrorHandler(Display * pDisplay) +winClipboardIOErrorHandler (Display *pDisplay) { - ErrorF("winClipboardIOErrorHandler!\n\n"); + ErrorF ("winClipboardIOErrorHandler!\n"); if (pthread_equal(pthread_self(), g_winClipboardProcThread)) { - /* Restart at the main entry point */ - longjmp(g_jmpEntry, WIN_JMP_ERROR_IO); + /* Restart at the main entry point */ + longjmp (g_jmpEntry, WIN_JMP_ERROR_IO); } - if (g_winClipboardOldIOErrorHandler) - g_winClipboardOldIOErrorHandler(pDisplay); + if (g_winClipboardOldIOErrorHandler) + g_winClipboardOldIOErrorHandler(pDisplay); + + return 0; +} - return 0; +/* + * winClipboardThreadExit - Thread exit handler + */ + +static void +winClipboardThreadExit(void *arg) +{ + /* clipboard thread has exited, stop server as well */ + kill(getpid(), SIGTERM); } |