FreeBSD Bugzilla – Attachment 223548 Details for
Bug 254451
graphics/mupdf: clipboard support for -gl
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
mupdf freeglut patch
freeglut.patch (text/plain), 39.89 KB, created by
yzrh
on 2021-03-24 15:56:46 UTC
(
hide
)
Description:
mupdf freeglut patch
Filename:
MIME Type:
Creator:
yzrh
Created:
2021-03-24 15:56:46 UTC
Size:
39.89 KB
patch
obsolete
>diff --git a/include/GL/freeglut_ext.h b/include/GL/freeglut_ext.h >index 0c22c4f..f12324a 100644 >--- a/include/GL/freeglut_ext.h >+++ b/include/GL/freeglut_ext.h >@@ -145,6 +145,7 @@ FGAPI void FGAPIENTRY glutSetMenuFont( int menuID, void* font ); > /* > * Window-specific callback functions, see fg_callbacks.c > */ >+FGAPI void FGAPIENTRY glutKeyboardExtFunc( void (* callback)( int, int, int ) ); > FGAPI void FGAPIENTRY glutMouseWheelFunc( void (* callback)( int, int, int, int ) ); > FGAPI void FGAPIENTRY glutPositionFunc( void (* callback)( int, int ) ); > FGAPI void FGAPIENTRY glutCloseFunc( void (* callback)( void ) ); >@@ -163,6 +164,15 @@ FGAPI void FGAPIENTRY glutSetWindowData(void* data); > FGAPI void* FGAPIENTRY glutGetMenuData( void ); > FGAPI void FGAPIENTRY glutSetMenuData(void* data); > >+/* >+ * Clipboard access >+ */ >+#define GLUT_CLIPBOARD 0 >+#define GLUT_PRIMARY 1 >+#define GLUT_SECONDARY 2 >+FGAPI void FGAPIENTRY glutSetClipboard(int selection, const char *string); >+FGAPI const char * FGAPIENTRY glutGetClipboard(int selection); >+ > /* > * Font stuff, see fg_font.c > */ >diff --git a/include/GL/freeglut_std.h b/include/GL/freeglut_std.h >index a658c7c..01b4611 100644 >--- a/include/GL/freeglut_std.h >+++ b/include/GL/freeglut_std.h >@@ -120,7 +120,7 @@ > * The freeglut and GLUT API versions > */ > #define FREEGLUT 1 >-#define GLUT_API_VERSION 4 >+#define GLUT_API_VERSION 6 > #define GLUT_XLIB_IMPLEMENTATION 13 > /* Deprecated: > cf. http://sourceforge.net/mailarchive/forum.php?thread_name=CABcAi1hw7cr4xtigckaGXB5X8wddLfMcbA_rZ3NAuwMrX_zmsw%40mail.gmail.com&forum_name=freeglut-developer */ >@@ -498,6 +498,7 @@ FGAPI void FGAPIENTRY glutMotionFunc( void (* callback)( int, int ) ); > FGAPI void FGAPIENTRY glutPassiveMotionFunc( void (* callback)( int, int ) ); > FGAPI void FGAPIENTRY glutEntryFunc( void (* callback)( int ) ); > >+FGAPI void FGAPIENTRY glutKeyboardDownFunc( void (* callback)( unsigned char, int, int ) ); > FGAPI void FGAPIENTRY glutKeyboardUpFunc( void (* callback)( unsigned char, int, int ) ); > FGAPI void FGAPIENTRY glutSpecialUpFunc( void (* callback)( int, int, int ) ); > FGAPI void FGAPIENTRY glutJoystickFunc( void (* callback)( unsigned int, int, int, int ), int pollInterval ); >diff --git a/src/fg_callbacks.c b/src/fg_callbacks.c >index 11924b3..bd5c21a 100644 >--- a/src/fg_callbacks.c >+++ b/src/fg_callbacks.c >@@ -124,6 +124,8 @@ void FGAPIENTRY glut##a##Func( FGCB##b callback ) \ > /* Implement all these callback setter functions... */ > IMPLEMENT_CALLBACK_FUNC(Position) > IMPLEMENT_CALLBACK_FUNC(Keyboard) >+IMPLEMENT_CALLBACK_FUNC(KeyboardExt) >+IMPLEMENT_CALLBACK_FUNC(KeyboardDown) > IMPLEMENT_CALLBACK_FUNC(KeyboardUp) > IMPLEMENT_CALLBACK_FUNC(Special) > IMPLEMENT_CALLBACK_FUNC(SpecialUp) >diff --git a/src/fg_ext.c b/src/fg_ext.c >index d96849a..0c79052 100644 >--- a/src/fg_ext.c >+++ b/src/fg_ext.c >@@ -111,6 +111,7 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName ) > CHECK_NAME(glutMenuStatusFunc); > CHECK_NAME(glutOverlayDisplayFunc); > CHECK_NAME(glutWindowStatusFunc); >+ CHECK_NAME(glutKeyboardDownFunc); > CHECK_NAME(glutKeyboardUpFunc); > CHECK_NAME(glutSpecialUpFunc); > CHECK_NAME(glutSetColor); >@@ -186,7 +187,10 @@ static GLUTproc fghGetGLUTProcAddress( const char* procName ) > CHECK_NAME(glutBitmapString); > CHECK_NAME(glutStrokeString); > CHECK_NAME(glutGetProcAddress); >+ CHECK_NAME(glutKeyboardExtFunc); > CHECK_NAME(glutMouseWheelFunc); >+ CHECK_NAME(glutGetClipboard); >+ CHECK_NAME(glutSetClipboard); > CHECK_NAME(glutJoystickGetNumAxes); > CHECK_NAME(glutJoystickGetNumButtons); > CHECK_NAME(glutJoystickNotWorking); >diff --git a/src/fg_internal.h b/src/fg_internal.h >index 3f0dc42..2b18f62 100644 >--- a/src/fg_internal.h >+++ b/src/fg_internal.h >@@ -210,6 +210,8 @@ typedef void (* FGCBReshape )( int, int ); > typedef void (* FGCBPosition )( int, int ); > typedef void (* FGCBVisibility )( int ); > typedef void (* FGCBKeyboard )( unsigned char, int, int ); >+typedef void (* FGCBKeyboardExt )( int, int, int ); >+typedef void (* FGCBKeyboardDown )( unsigned char, int, int ); > typedef void (* FGCBKeyboardUp )( unsigned char, int, int ); > typedef void (* FGCBSpecial )( int, int, int ); > typedef void (* FGCBSpecialUp )( int, int, int ); >@@ -595,6 +597,8 @@ enum > WCB_Reshape, > WCB_Position, > WCB_Keyboard, >+ WCB_KeyboardExt, >+ WCB_KeyboardDown, > WCB_KeyboardUp, > WCB_Special, > WCB_SpecialUp, >@@ -1061,6 +1065,9 @@ void fgWarning( const char *fmt, ... ); > > SFG_Proc fgPlatformGetProcAddress( const char *procName ); > >+void fgPlatformSetClipboard(int selection, const char *text); >+const char *fgPlatformGetClipboard(int selection); >+ > /* pushing attribute/value pairs into an array */ > #define ATTRIB(a) attributes[where++]=(a) > #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);} >diff --git a/src/fg_window.c b/src/fg_window.c >index 09fcddf..3e24ffd 100644 >--- a/src/fg_window.c >+++ b/src/fg_window.c >@@ -357,6 +357,29 @@ void FGAPIENTRY glutSetIconTitle( const char* title ) > } > } > >+/* >+ * This function sets the clipboard content to the UTF-8 encoded text. >+ */ >+void FGAPIENTRY glutSetClipboard(int selection, const char *text) >+{ >+ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetClipboard" ); >+ FREEGLUT_EXIT_IF_NO_WINDOW ( "glutSetClipboard" ); >+ >+ fgPlatformSetClipboard(selection, text); >+} >+ >+/* >+ * This function returns the clipboard content as UTF-8 encoded text, >+ * or NULL if no content was available. >+ */ >+const char* FGAPIENTRY glutGetClipboard(int selection) >+{ >+ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutGetClipboard" ); >+ FREEGLUT_EXIT_IF_NO_WINDOW ( "glutGetClipboard" ); >+ >+ return fgPlatformGetClipboard(selection); >+} >+ > /* > * Change the current window's size > */ >diff --git a/src/freeglutdll.def.in b/src/freeglutdll.def.in >index 988d7d3..a0b80c6 100644 >--- a/src/freeglutdll.def.in >+++ b/src/freeglutdll.def.in >@@ -65,6 +65,8 @@ EXPORTS > glutEntryFunc > glutCloseFunc > glutWMCloseFunc >+ glutKeyboardExtFunc >+ glutKeyboardDownFunc > glutKeyboardUpFunc > glutSpecialUpFunc > glutJoystickFunc >diff --git a/src/mswin/fg_init_mswin.c b/src/mswin/fg_init_mswin.c >index b1c51da..d68a2a4 100644 >--- a/src/mswin/fg_init_mswin.c >+++ b/src/mswin/fg_init_mswin.c >@@ -36,6 +36,8 @@ extern LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, > extern void fgPlatformInitSystemTime(); > extern void fghCloseInputDevices(void); > >+char *fgClipboardBuffer[3] = { NULL, NULL, NULL }; >+ > > /* > * A call to this function should initialize all the display stuff... >@@ -150,12 +152,20 @@ void fgPlatformDeinitialiseInputDevices ( void ) > > void fgPlatformCloseDisplay ( void ) > { >+ int i; >+ > if( fgDisplay.pDisplay.DisplayName ) > { > free( fgDisplay.pDisplay.DisplayName ); > fgDisplay.pDisplay.DisplayName = NULL; > } > >+ for (i = 0; i < 3; ++i) >+ { >+ free(fgClipboardBuffer[i]); >+ fgClipboardBuffer[i] = NULL; >+ } >+ > /* Reset the timer granularity */ > timeEndPeriod ( 1 ); > } >diff --git a/src/mswin/fg_main_mswin.c b/src/mswin/fg_main_mswin.c >index 54ec12c..f9fbdab 100644 >--- a/src/mswin/fg_main_mswin.c >+++ b/src/mswin/fg_main_mswin.c >@@ -28,6 +28,10 @@ > #include <GL/freeglut.h> > #include "../fg_internal.h" > >+#ifndef MAPVK_VK_TO_CHAR >+#define MAPVK_VK_TO_CHAR 2 >+#endif >+ > extern void fghRedrawWindow ( SFG_Window *window ); > extern void fghRedrawWindowAndChildren ( SFG_Window *window ); > extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify); >@@ -480,6 +484,81 @@ fg_time_t fgPlatformSystemTime ( void ) > return currTime32 | timeEpoch << 32; > } > >+extern char *fgClipboardBuffer[3]; >+ >+void fgPlatformSetClipboard(int selection, const char *text) >+{ >+ if (selection == GLUT_PRIMARY) >+ { >+ free(fgClipboardBuffer[GLUT_PRIMARY]); >+ fgClipboardBuffer[GLUT_PRIMARY] = strdup(text); >+ } >+ else if (selection == GLUT_SECONDARY) >+ { >+ free(fgClipboardBuffer[GLUT_SECONDARY]); >+ fgClipboardBuffer[GLUT_SECONDARY] = strdup(text); >+ } >+ else if (selection == GLUT_CLIPBOARD && text) >+ { >+ int n = MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0); >+ if (n > 0) >+ { >+ HANDLE object = GlobalAlloc(0, n * sizeof(WCHAR)); >+ if (object) >+ { >+ WCHAR *wtext = GlobalLock(object); >+ if (wtext) >+ { >+ MultiByteToWideChar(CP_UTF8, 0, text, -1, wtext, n); >+ GlobalUnlock(object); >+ if (OpenClipboard(NULL)) >+ { >+ EmptyClipboard(); >+ SetClipboardData(CF_UNICODETEXT, object); >+ CloseClipboard(); >+ } >+ } >+ GlobalFree(object); >+ } >+ } >+ } >+} >+ >+const char *fgPlatformGetClipboard(int selection) >+{ >+ if (selection == GLUT_PRIMARY) >+ return fgClipboardBuffer[GLUT_PRIMARY]; >+ if (selection == GLUT_SECONDARY) >+ return fgClipboardBuffer[GLUT_SECONDARY]; >+ if (selection == GLUT_CLIPBOARD) >+ { >+ free(fgClipboardBuffer[GLUT_CLIPBOARD]); >+ fgClipboardBuffer[GLUT_CLIPBOARD] = NULL; >+ if (OpenClipboard(NULL)) >+ { >+ HANDLE object = GetClipboardData(CF_UNICODETEXT); >+ if (object) >+ { >+ WCHAR *wtext = GlobalLock(object); >+ if (wtext) >+ { >+ int n = WideCharToMultiByte(CP_UTF8, 0, wtext, -1, NULL, 0, NULL, NULL); >+ if (n > 0) >+ { >+ char *text = malloc(n); >+ fgClipboardBuffer[GLUT_CLIPBOARD] = text; >+ WideCharToMultiByte(CP_UTF8, 0, wtext, -1, text, n, NULL, NULL); >+ } >+ GlobalUnlock(object); >+ } >+ GlobalFree(object); >+ } >+ CloseClipboard(); >+ } >+ return fgClipboardBuffer[GLUT_CLIPBOARD]; >+ } >+ return NULL; >+} > > void fgPlatformSleepForEvents( fg_time_t msec ) > { >@@ -664,9 +743,17 @@ static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean ke > case VK_DELETE: > /* The delete key should be treated as an ASCII keypress: */ > if (keydown) >+ { >+ INVOKE_WCB( *window, KeyboardDown, >+ ( 127, window->State.MouseX, window->State.MouseY ) >+ ); >+ INVOKE_WCB( *window, KeyboardExt, >+ ( 127, window->State.MouseX, window->State.MouseY ) >+ ); > INVOKE_WCB( *window, Keyboard, > ( 127, window->State.MouseX, window->State.MouseY ) > ); >+ } > else > INVOKE_WCB( *window, KeyboardUp, > ( 127, window->State.MouseX, window->State.MouseY ) >@@ -675,21 +762,19 @@ static LRESULT fghWindowProcKeyPress(SFG_Window *window, UINT uMsg, GLboolean ke > > #if !defined(_WIN32_WCE) > default: >- /* keydown displayable characters are handled with WM_CHAR message, but no corresponding up is generated. So get that here. */ >- if (!keydown) >+ /* Mapped characters are handled with the WM_CHAR message. Handle low-level ASCII press/release callbacks here. */ > { >- BYTE state[ 256 ]; >- WORD code[ 2 ]; >- >- GetKeyboardState( state ); >- >- if( ToAscii( (UINT)wParam, 0, state, code, 0 ) == 1 ) >- wParam=code[ 0 ]; >- >- INVOKE_WCB( *window, KeyboardUp, >- ( (char)(wParam & 0xFF), /* and with 0xFF to indicate to runtime that we want to strip out higher bits - otherwise we get a runtime error when "Smaller Type Checks" is enabled */ >- window->State.MouseX, window->State.MouseY ) >- ); >+ UINT ascii = (UINT)MapVirtualKey((UINT)wParam, MAPVK_VK_TO_CHAR); >+ if (ascii >= 32 && ascii < 256) >+ { >+ /* Always send lowercase (unshifted) values */ >+ if (ascii >= 'A' && ascii <= 'Z') >+ ascii = ascii - 'A' + 'a'; >+ if (keydown) >+ INVOKE_WCB(*window, KeyboardDown, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) ); >+ else >+ INVOKE_WCB(*window, KeyboardUp, ((unsigned char)ascii, window->State.MouseX, window->State.MouseY) ); >+ } > } > #endif > } >@@ -1375,10 +1460,13 @@ LRESULT CALLBACK fgPlatformWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPAR > break; > > fgState.Modifiers = fgPlatformGetModifiers( ); >- INVOKE_WCB( *window, Keyboard, >- ( (char)wParam, >- window->State.MouseX, window->State.MouseY ) >+ INVOKE_WCB( *window, KeyboardExt, >+ ( (int)wParam, window->State.MouseX, window->State.MouseY ) > ); >+ if (wParam < 256) >+ INVOKE_WCB( *window, Keyboard, >+ ( (unsigned char)wParam, window->State.MouseX, window->State.MouseY ) >+ ); > fgState.Modifiers = INVALID_MODIFIERS; > } > break; >diff --git a/src/x11/fg_init_x11.c b/src/x11/fg_init_x11.c >index d2907c9..62b64fd 100644 >--- a/src/x11/fg_init_x11.c >+++ b/src/x11/fg_init_x11.c >@@ -33,12 +33,16 @@ > #include "fg_init.h" > #include "egl/fg_init_egl.h" > >+#include <locale.h> >+ > /* Return the atom associated with "name". */ > static Atom fghGetAtom(const char * name) > { > return XInternAtom(fgDisplay.pDisplay.Display, name, False); > } > >+char *fgClipboardBuffer[3] = { NULL, NULL, NULL }; >+ > /* > * Check if "property" is set on "window". The property's values are returned > * through "data". If the property is set and is of type "type", return the >@@ -256,10 +260,46 @@ void fgPlatformInitialize( const char* displayName ) > fgDisplay.pDisplay.ClientMachine = fghGetAtom("WM_CLIENT_MACHINE"); > } > >+ /* Open an input method */ >+ setlocale(LC_ALL, ""); /* ugh! but we can't force the client to do it for us... */ >+ if (!XSupportsLocale()) >+ fgWarning("X doesn't support the current locale."); >+ if (!XSetLocaleModifiers("")) >+ fgWarning("Couldn't set X locale modifiers."); >+ fgDisplay.pDisplay.IM = XOpenIM(fgDisplay.pDisplay.Display, NULL, NULL, NULL); >+ if (!fgDisplay.pDisplay.IM) >+ fgWarning("Couldn't open X input method."); >+ else >+ { >+ XIMStyles *styles; >+ XIMStyle supported = XIMPreeditNothing | XIMStatusNothing; >+ XIMStyle best = 0; >+ unsigned int i; >+ char *res = XGetIMValues(fgDisplay.pDisplay.IM, XNQueryInputStyle, &styles, NULL); >+ if (res) >+ fgWarning("Couldn't get input method style: %s.", res); >+ else >+ { >+ for (i = 0; i < styles->count_styles; ++i) >+ { >+ XIMStyle style = styles->supported_styles[i]; >+ if ((style & supported) == style) >+ best = style; >+ } >+ fgDisplay.pDisplay.InputStyle = best; >+ } >+ XFree(styles); >+ if (best == 0) >+ { >+ fgWarning("Couldn't find a usable input method style."); >+ XCloseIM(fgDisplay.pDisplay.IM); >+ fgDisplay.pDisplay.IM = NULL; >+ } >+ } >+ > /* Get start time */ > fgState.Time = fgSystemTime(); > >- > fgState.Initialised = GL_TRUE; > > atexit(fgDeinitialize); >@@ -279,17 +319,28 @@ void fgPlatformDeinitialiseInputDevices ( void ) > > void fgPlatformCloseDisplay ( void ) > { >+ int i; >+ > /* > * Make sure all X-client data we have created will be destroyed on > * display closing > */ > XSetCloseDownMode( fgDisplay.pDisplay.Display, DestroyAll ); > >+ if (fgDisplay.pDisplay.IM) >+ XCloseIM(fgDisplay.pDisplay.IM); >+ > /* > * Close the display connection, destroying all windows we have > * created so far > */ > XCloseDisplay( fgDisplay.pDisplay.Display ); >+ >+ for (i = 0; i < 3; ++i) >+ { >+ free(fgClipboardBuffer[i]); >+ fgClipboardBuffer[i] = NULL; >+ } > } > > >diff --git a/src/x11/fg_internal_x11.h b/src/x11/fg_internal_x11.h >index 09a238a..4b15584 100644 >--- a/src/x11/fg_internal_x11.h >+++ b/src/x11/fg_internal_x11.h >@@ -63,6 +63,8 @@ struct tagSFG_PlatformDisplay > int NetWMSupported; /* Flag for EWMH Window Managers */ > Atom NetWMPid; /* The _NET_WM_PID atom */ > Atom ClientMachine; /* The client machine name atom */ >+ XIM IM; /* The input method */ >+ XIMStyle InputStyle; /* The input method style */ > > #ifdef HAVE_X11_EXTENSIONS_XRANDR_H > int prev_xsz, prev_ysz; >@@ -107,6 +109,7 @@ struct tagSFG_PlatformContext > #else > GLXFBConfig FBConfig; /* The window's FBConfig */ > #endif >+ XIC IC; /* The window's input context */ > }; > > >diff --git a/src/x11/fg_main_x11.c b/src/x11/fg_main_x11.c >index 0e54253..bfb4f8f 100644 >--- a/src/x11/fg_main_x11.c >+++ b/src/x11/fg_main_x11.c >@@ -29,8 +29,9 @@ > #include <GL/freeglut.h> > #include "../fg_internal.h" > #include <errno.h> >+#include <limits.h> > #include <stdarg.h> >- >+#include <sys/select.h> > > /* > * Try to get the maximum value allowed for ints, falling back to the minimum >@@ -579,6 +580,285 @@ __fg_unused static void fghPrintEvent( XEvent *event ) > } > } > >+/* UTF-8 decoding routine */ >+enum >+{ >+ Runeerror = 0xFFFD, /* decoding error in UTF */ >+ >+ Bit1 = 7, >+ Bitx = 6, >+ Bit2 = 5, >+ Bit3 = 4, >+ Bit4 = 3, >+ Bit5 = 2, >+ >+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */ >+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */ >+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */ >+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */ >+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */ >+ T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */ >+ >+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */ >+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */ >+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */ >+ Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */ >+ >+ Maskx = (1<<Bitx)-1, /* 0011 1111 */ >+ Testx = Maskx ^ 0xFF, /* 1100 0000 */ >+ >+ Bad = Runeerror, >+}; >+ >+static int chartorune(int *rune, const char *str) >+{ >+ int c, c1, c2, c3; >+ int l; >+ >+ /* >+ * one character sequence >+ * 00000-0007F => T1 >+ */ >+ c = *(const unsigned char*)str; >+ if(c < Tx) { >+ *rune = c; >+ return 1; >+ } >+ >+ /* >+ * two character sequence >+ * 0080-07FF => T2 Tx >+ */ >+ c1 = *(const unsigned char*)(str+1) ^ Tx; >+ if(c1 & Testx) >+ goto bad; >+ if(c < T3) { >+ if(c < T2) >+ goto bad; >+ l = ((c << Bitx) | c1) & Rune2; >+ if(l <= Rune1) >+ goto bad; >+ *rune = l; >+ return 2; >+ } >+ >+ /* >+ * three character sequence >+ * 0800-FFFF => T3 Tx Tx >+ */ >+ c2 = *(const unsigned char*)(str+2) ^ Tx; >+ if(c2 & Testx) >+ goto bad; >+ if(c < T4) { >+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3; >+ if(l <= Rune2) >+ goto bad; >+ *rune = l; >+ return 3; >+ } >+ >+ /* >+ * four character sequence (21-bit value) >+ * 10000-1FFFFF => T4 Tx Tx Tx >+ */ >+ c3 = *(const unsigned char*)(str+3) ^ Tx; >+ if (c3 & Testx) >+ goto bad; >+ if (c < T5) { >+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4; >+ if (l <= Rune3) >+ goto bad; >+ *rune = l; >+ return 4; >+ } >+ /* >+ * Support for 5-byte or longer UTF-8 would go here, but >+ * since we don't have that, we'll just fall through to bad. >+ */ >+ >+ /* >+ * bad decoding >+ */ >+bad: >+ *rune = Bad; >+ return 1; >+} >+ >+extern char *fgClipboardBuffer[3]; >+ >+static Atom fghGetAtom(const char *name) >+{ >+ return XInternAtom(fgDisplay.pDisplay.Display, name, False); >+} >+ >+static void fgHandleSelectionNotify(XEvent *event) >+{ >+ Display *dpy = fgDisplay.pDisplay.Display; >+ Atom actual_type; >+ int actual_format; >+ unsigned long item_count; >+ unsigned long bytes_after; >+ unsigned char *prop; >+ >+ if (event->xselection.property == None) >+ { >+ fgWarning("Couldn't convert selection to UTF-8 string."); >+ return; >+ } >+ >+ XGetWindowProperty(dpy, event->xselection.requestor, event->xselection.property, >+ 0, LONG_MAX, True, AnyPropertyType, >+ &actual_type, &actual_format, &item_count, &bytes_after, &prop); >+ >+ if (actual_type == fghGetAtom("UTF8_STRING")) >+ { >+ if (event->xselection.selection == fghGetAtom("CLIPBOARD")) >+ { >+ free(fgClipboardBuffer[GLUT_CLIPBOARD]); >+ fgClipboardBuffer[GLUT_CLIPBOARD] = strdup((char*)prop); >+ } >+ if (event->xselection.selection == XA_PRIMARY) >+ { >+ free(fgClipboardBuffer[GLUT_PRIMARY]); >+ fgClipboardBuffer[GLUT_PRIMARY] = strdup((char*)prop); >+ } >+ if (event->xselection.selection == XA_SECONDARY) >+ { >+ free(fgClipboardBuffer[GLUT_SECONDARY]); >+ fgClipboardBuffer[GLUT_SECONDARY] = strdup((char*)prop); >+ } >+ } >+ >+ XFree(prop); >+} >+ >+static void fgHandleSelectionClear(XEvent *event) >+{ >+ if (event->xselectionclear.selection == fghGetAtom("CLIPBOARD")) >+ { >+ free(fgClipboardBuffer[GLUT_CLIPBOARD]); >+ fgClipboardBuffer[GLUT_CLIPBOARD] = NULL; >+ } >+ else if (event->xselectionclear.selection == XA_PRIMARY) >+ { >+ free(fgClipboardBuffer[GLUT_PRIMARY]); >+ fgClipboardBuffer[GLUT_PRIMARY] = NULL; >+ } >+ else if (event->xselectionclear.selection == XA_SECONDARY) >+ { >+ free(fgClipboardBuffer[GLUT_SECONDARY]); >+ fgClipboardBuffer[GLUT_SECONDARY] = NULL; >+ } >+} >+ >+static void fgHandleSelectionRequest(XEvent *event) >+{ >+ Display *dpy = fgDisplay.pDisplay.Display; >+ Window requestor = event->xselectionrequest.requestor; >+ Atom selection = event->xselectionrequest.selection; >+ Atom target = event->xselectionrequest.target; >+ Atom property = event->xselectionrequest.property; >+ Atom time = event->xselectionrequest.time; >+ XEvent response; >+ char *text; >+ >+ if (property == None) >+ property = target; >+ >+ response.xselection.type = SelectionNotify; >+ response.xselection.send_event = True; >+ response.xselection.display = dpy; >+ response.xselection.requestor = requestor; >+ response.xselection.selection = selection; >+ response.xselection.target = target; >+ response.xselection.property = property; >+ response.xselection.time = time; >+ >+ if (selection == fghGetAtom("CLIPBOARD")) >+ text = fgClipboardBuffer[GLUT_CLIPBOARD]; >+ else if (selection == XA_PRIMARY) >+ text = fgClipboardBuffer[GLUT_PRIMARY]; >+ else if (selection == XA_SECONDARY) >+ text = fgClipboardBuffer[GLUT_SECONDARY]; >+ else >+ return; >+ if (!text) >+ return; >+ >+ if (target == fghGetAtom("TARGETS")) >+ { >+ Atom list[4] = { >+ fghGetAtom("TARGETS"), >+ fghGetAtom("TIMESTAMP"), >+ XA_STRING, >+ fghGetAtom("UTF8_STRING") >+ }; >+ XChangeProperty(dpy, requestor, property, target, >+ 32, PropModeReplace, (unsigned char *)list, sizeof(list)/sizeof(Atom)); >+ } >+ else if (target == XA_STRING || target == fghGetAtom("UTF8_STRING")) >+ { >+ XChangeProperty(dpy, requestor, property, target, >+ 8, PropModeReplace, (unsigned char *)text, strlen(text)); >+ } >+ >+ XSendEvent(dpy, requestor, False, 0, &response); >+} >+ >+void fgPlatformSetClipboard(int selection, const char *text) >+{ >+ Display *dpy = fgDisplay.pDisplay.Display; >+ Window window = fgStructure.CurrentWindow->Window.Handle; >+ Atom xselection; >+ if (selection == GLUT_CLIPBOARD) >+ xselection = fghGetAtom("CLIPBOARD"); >+ else if (selection == GLUT_PRIMARY) >+ xselection = XA_PRIMARY; >+ else if (selection == GLUT_SECONDARY) >+ xselection = XA_SECONDARY; >+ else >+ return; >+ >+ free(fgClipboardBuffer[selection]); >+ fgClipboardBuffer[selection] = strdup(text); >+ >+ XSetSelectionOwner(dpy, xselection, window, CurrentTime); >+} >+ >+static Bool isSelectionNotify(Display *dpi, XEvent *event, XPointer arg) >+{ >+ return (event->type == SelectionNotify); >+} >+ >+const char *fgPlatformGetClipboard(int selection) >+{ >+ Display *dpy = fgDisplay.pDisplay.Display; >+ Window window = fgStructure.CurrentWindow->Window.Handle; >+ Atom xselection; >+ Window owner; >+ XEvent event; >+ >+ if (selection == GLUT_CLIPBOARD) >+ xselection = fghGetAtom("CLIPBOARD"); >+ else if (selection == GLUT_PRIMARY) >+ xselection = XA_PRIMARY; >+ else if (selection == GLUT_SECONDARY) >+ xselection = XA_SECONDARY; >+ else >+ return NULL; >+ >+ owner = XGetSelectionOwner(dpy, xselection); >+ if (!owner) >+ return NULL; >+ if (owner != window) >+ { >+ XConvertSelection(dpy, xselection, fghGetAtom("UTF8_STRING"), xselection, window, CurrentTime); >+ XIfEvent(dpy, &event, isSelectionNotify, NULL); >+ fgHandleSelectionNotify(&event); >+ } >+ >+ return fgClipboardBuffer[selection]; >+} > > void fgPlatformProcessSingleEvent ( void ) > { >@@ -603,6 +883,8 @@ void fgPlatformProcessSingleEvent ( void ) > #if _DEBUG > fghPrintEvent( &event ); > #endif >+ if (XFilterEvent(&event, None)) >+ continue; > > switch( event.type ) > { >@@ -631,6 +913,16 @@ void fgPlatformProcessSingleEvent ( void ) > } > break; > >+ case SelectionClear: >+ fgHandleSelectionClear(&event); >+ break; >+ case SelectionRequest: >+ fgHandleSelectionRequest(&event); >+ break; >+ case SelectionNotify: >+ fgHandleSelectionNotify(&event); >+ break; >+ > /* > * CreateNotify causes a configure-event so that sub-windows are > * handled compatibly with GLUT. Otherwise, your sub-windows >@@ -890,8 +1182,10 @@ void fgPlatformProcessSingleEvent ( void ) > case KeyRelease: > case KeyPress: > { >- FGCBKeyboard keyboard_cb; >+ FGCBKeyboardExt keyboard_ext_cb; >+ FGCBKeyboard keyboard_cb, keyboard_low_cb; > FGCBSpecial special_cb; >+ int did_keyboard_cb = 0; > > GETWINDOW( xkey ); > GETMOUSE( xkey ); >@@ -932,108 +1226,154 @@ void fgPlatformProcessSingleEvent ( void ) > > if( event.type == KeyPress ) > { >+ keyboard_ext_cb = (FGCBKeyboardExt)( FETCH_WCB( *window, KeyboardExt )); >+ keyboard_low_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardDown )); > keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard )); > special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special )); > } > else > { >- keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); >+ keyboard_ext_cb = NULL; >+ keyboard_low_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp )); >+ keyboard_cb = NULL; > special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp )); > } > >- /* Is there a keyboard/special callback hooked for this window? */ >- if( keyboard_cb || special_cb ) >+ /* Is there a character keyboard callback hooked for this window? */ >+ if (keyboard_ext_cb || keyboard_cb) > { >- XComposeStatus composeStatus; >- char asciiCode[ 32 ]; >+ static XComposeStatus composeStatus = { 0 }; /* keep state across invocations */ >+ XIC ic = window->Window.pContext.IC; >+ Status status; >+ char buf[32], *utf8 = buf; > KeySym keySym; >- int len; >+ int i, c, len; > >- /* Check for the ASCII/KeySym codes associated with the event: */ >- len = XLookupString( &event.xkey, asciiCode, sizeof(asciiCode), >- &keySym, &composeStatus >- ); >- >- /* GLUT API tells us to have two separate callbacks... */ >- if( len > 0 ) >+ /* Check for the Unicode text associated with the event: */ >+ if (ic) > { >- /* ...one for the ASCII translateable keypresses... */ >- if( keyboard_cb ) >+ len = Xutf8LookupString(ic, &event.xkey, buf, sizeof buf, &keySym, &status); >+ if (status == XBufferOverflow) > { >- fgSetWindow( window ); >- fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); >- keyboard_cb( asciiCode[ 0 ], >- event.xkey.x, event.xkey.y >- ); >- fgState.Modifiers = INVALID_MODIFIERS; >+ utf8 = malloc(len); >+ len = Xutf8LookupString(ic, &event.xkey, utf8, len, &keySym, &status); > } > } > else > { >- int special = -1; >+ len = XLookupString(&event.xkey, buf, sizeof buf, &keySym, &composeStatus); >+ } > >- /* >- * ...and one for all the others, which need to be >- * translated to GLUT_KEY_Xs... >- */ >- switch( keySym ) >- { >- case XK_F1: special = GLUT_KEY_F1; break; >- case XK_F2: special = GLUT_KEY_F2; break; >- case XK_F3: special = GLUT_KEY_F3; break; >- case XK_F4: special = GLUT_KEY_F4; break; >- case XK_F5: special = GLUT_KEY_F5; break; >- case XK_F6: special = GLUT_KEY_F6; break; >- case XK_F7: special = GLUT_KEY_F7; break; >- case XK_F8: special = GLUT_KEY_F8; break; >- case XK_F9: special = GLUT_KEY_F9; break; >- case XK_F10: special = GLUT_KEY_F10; break; >- case XK_F11: special = GLUT_KEY_F11; break; >- case XK_F12: special = GLUT_KEY_F12; break; >- >- case XK_KP_Left: >- case XK_Left: special = GLUT_KEY_LEFT; break; >- case XK_KP_Right: >- case XK_Right: special = GLUT_KEY_RIGHT; break; >- case XK_KP_Up: >- case XK_Up: special = GLUT_KEY_UP; break; >- case XK_KP_Down: >- case XK_Down: special = GLUT_KEY_DOWN; break; >- >- case XK_KP_Prior: >- case XK_Prior: special = GLUT_KEY_PAGE_UP; break; >- case XK_KP_Next: >- case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; >- case XK_KP_Home: >- case XK_Home: special = GLUT_KEY_HOME; break; >- case XK_KP_End: >- case XK_End: special = GLUT_KEY_END; break; >- case XK_KP_Insert: >- case XK_Insert: special = GLUT_KEY_INSERT; break; >- >- case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; >- case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; >- case XK_KP_Delete: special = GLUT_KEY_DELETE; break; >- >- case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; >- case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; >- case XK_Control_L: special = GLUT_KEY_CTRL_L; break; >- case XK_Control_R: special = GLUT_KEY_CTRL_R; break; >- case XK_Alt_L: special = GLUT_KEY_ALT_L; break; >- case XK_Alt_R: special = GLUT_KEY_ALT_R; break; >- } >+ if (len > 0) >+ { >+ fgSetWindow(window); >+ fgState.Modifiers = fgPlatformGetModifiers(event.xkey.state); > >- /* >- * Execute the callback (if one has been specified), >- * given that the special code seems to be valid... >- */ >- if( special_cb && (special != -1) ) >+ i = 0; >+ while (i < len) > { >- fgSetWindow( window ); >- fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); >- special_cb( special, event.xkey.x, event.xkey.y ); >- fgState.Modifiers = INVALID_MODIFIERS; >+ i += chartorune(&c, utf8 + i); >+ >+ /* ...for the Unicode translateable keypresses... */ >+ if (keyboard_ext_cb) >+ keyboard_ext_cb(c, event.xkey.x, event.xkey.y); >+ >+ /* ...for the Latin-1 translateable keypresses... */ >+ if (keyboard_cb) >+ if (c < 256) >+ keyboard_cb(c, event.xkey.x, event.xkey.y); > } >+ >+ fgState.Modifiers = INVALID_MODIFIERS; >+ >+ did_keyboard_cb = 1; >+ } >+ >+ if (utf8 != buf) >+ free(utf8); >+ } >+ >+ /* Is there a low-level keyboard callback hooked for this window? */ >+ if (keyboard_low_cb || special_cb) >+ { >+ int special = -1; >+ int ascii = 0; >+ >+ KeySym keySym = XLookupKeysym(&event.xkey, 0); >+ >+ /* ...for low-level keys, which need to be >+ * translated to GLUT_KEY_Xs or ASCII values... >+ */ >+ switch( keySym ) >+ { >+ case XK_F1: special = GLUT_KEY_F1; break; >+ case XK_F2: special = GLUT_KEY_F2; break; >+ case XK_F3: special = GLUT_KEY_F3; break; >+ case XK_F4: special = GLUT_KEY_F4; break; >+ case XK_F5: special = GLUT_KEY_F5; break; >+ case XK_F6: special = GLUT_KEY_F6; break; >+ case XK_F7: special = GLUT_KEY_F7; break; >+ case XK_F8: special = GLUT_KEY_F8; break; >+ case XK_F9: special = GLUT_KEY_F9; break; >+ case XK_F10: special = GLUT_KEY_F10; break; >+ case XK_F11: special = GLUT_KEY_F11; break; >+ case XK_F12: special = GLUT_KEY_F12; break; >+ >+ case XK_KP_Left: >+ case XK_Left: special = GLUT_KEY_LEFT; break; >+ case XK_KP_Right: >+ case XK_Right: special = GLUT_KEY_RIGHT; break; >+ case XK_KP_Up: >+ case XK_Up: special = GLUT_KEY_UP; break; >+ case XK_KP_Down: >+ case XK_Down: special = GLUT_KEY_DOWN; break; >+ >+ case XK_KP_Prior: >+ case XK_Prior: special = GLUT_KEY_PAGE_UP; break; >+ case XK_KP_Next: >+ case XK_Next: special = GLUT_KEY_PAGE_DOWN; break; >+ case XK_KP_Home: >+ case XK_Home: special = GLUT_KEY_HOME; break; >+ case XK_KP_End: >+ case XK_End: special = GLUT_KEY_END; break; >+ case XK_KP_Insert: >+ case XK_Insert: special = GLUT_KEY_INSERT; break; >+ >+ case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break; >+ case XK_KP_Begin : special = GLUT_KEY_BEGIN; break; >+ case XK_KP_Delete: special = GLUT_KEY_DELETE; break; >+ >+ case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break; >+ case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break; >+ case XK_Control_L: special = GLUT_KEY_CTRL_L; break; >+ case XK_Control_R: special = GLUT_KEY_CTRL_R; break; >+ case XK_Alt_L: special = GLUT_KEY_ALT_L; break; >+ case XK_Alt_R: special = GLUT_KEY_ALT_R; break; >+ default: >+ if( keySym >= XK_space && keySym <= XK_ydiaeresis ) >+ ascii = keySym; >+ break; >+ } >+ >+ /* >+ * Execute the callback (if one has been specified), >+ * given that the special code seems to be valid... >+ * But only if we haven't already sent translated text for it, >+ * such as numeric keypad keys with numlock on. >+ */ >+ if( special_cb && (special != -1) && !did_keyboard_cb ) >+ { >+ fgSetWindow( window ); >+ fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); >+ special_cb( special, event.xkey.x, event.xkey.y ); >+ fgState.Modifiers = INVALID_MODIFIERS; >+ } >+ else if( keyboard_low_cb && (ascii >= 32 && ascii < 256) ) >+ { >+ fgSetWindow( window ); >+ fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state ); >+ keyboard_low_cb( ascii, event.xkey.x, event.xkey.y ); >+ fgState.Modifiers = INVALID_MODIFIERS; > } > } > } >diff --git a/src/x11/fg_window_x11.c b/src/x11/fg_window_x11.c >index 90f1966..f097d39 100644 >--- a/src/x11/fg_window_x11.c >+++ b/src/x11/fg_window_x11.c >@@ -154,6 +154,7 @@ void fgPlatformOpenWindow( SFG_Window* window, const char* title, > unsigned long mask; > unsigned int current_DisplayMode = fgState.DisplayMode ; > XEvent fakeEvent = {0}; >+ long event_mask; > > /* Save the display mode if we are creating a menu window */ > if( window->IsMenu && ( ! fgStructure.MenuContext ) ) >@@ -223,11 +224,6 @@ void fgPlatformOpenWindow( SFG_Window* window, const char* title, > * XXX more pleasant to trace. (Think mouse-motion! Tons of > * XXX ``bonus'' GUI events stream in.) > */ >- winAttr.event_mask = >- StructureNotifyMask | SubstructureNotifyMask | ExposureMask | >- ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | >- VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | >- PointerMotionMask | ButtonMotionMask; > winAttr.background_pixmap = None; > winAttr.background_pixel = 0; > winAttr.border_pixel = 0; >@@ -237,7 +233,7 @@ void fgPlatformOpenWindow( SFG_Window* window, const char* title, > visualInfo->visual, AllocNone > ); > >- mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask; >+ mask = CWBackPixmap | CWBorderPixel | CWColormap; > > if( window->IsMenu || ( gameMode == GL_TRUE ) ) > { >@@ -260,6 +256,29 @@ void fgPlatformOpenWindow( SFG_Window* window, const char* title, > &winAttr > ); > >+ event_mask = >+ StructureNotifyMask | SubstructureNotifyMask | ExposureMask | >+ ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | >+ VisibilityChangeMask | EnterWindowMask | LeaveWindowMask | >+ PointerMotionMask | ButtonMotionMask; >+ >+ /* Create input context */ >+ window->Window.pContext.IC = NULL; >+ if (fgDisplay.pDisplay.IM) >+ { >+ long im_event_mask; >+ window->Window.pContext.IC = >+ XCreateIC(fgDisplay.pDisplay.IM, >+ XNInputStyle, fgDisplay.pDisplay.InputStyle, >+ XNClientWindow, window->Window.Handle, >+ XNFocusWindow, window->Window.Handle, >+ NULL); >+ XGetICValues(window->Window.pContext.IC, XNFilterEvents, &im_event_mask, NULL); >+ event_mask |= im_event_mask; >+ XSetICFocus(window->Window.pContext.IC); >+ } >+ XSelectInput(fgDisplay.pDisplay.Display, window->Window.Handle, event_mask); >+ > /* Fake configure event to force viewport setup > * even with no window manager. > */ >@@ -466,6 +485,10 @@ void fgPlatformCloseWindow( SFG_Window* window ) > window->Window.pContext.FBConfig = NULL; > #endif > >+ if (window->Window.pContext.IC) { >+ XDestroyIC(window->Window.pContext.IC); >+ } >+ > if( window->Window.Handle ) { > XDestroyWindow( fgDisplay.pDisplay.Display, window->Window.Handle ); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 254451
:
223520
| 223548