diff options
author | Sven Gothel <[email protected]> | 2010-05-04 14:16:33 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-05-04 14:16:33 +0200 |
commit | 7613753091793b27a90585094aadb7beb36aab4b (patch) | |
tree | 1ebbb9b03683305d6e3197f3ae33d8ed75dfeece | |
parent | 7fad4be03e6d9987be420444364b6714667d32cc (diff) |
NEWT Fixes (Windows/child-win):
- Clarify NEWT setSize/setPosition in regards to fullscreen state
- Windows: Allow child win to receive keyboard events
- requestFocus: calls SetForegroundWindow and SetFocus
- requestFocus when mouse clicked
- add WS_TABSTOP
- Windows: Allow child win to set position
- TODO: child-win fullscreen as in X11 ..
-rw-r--r-- | make/scripts/java-win32-dbg.bat | 2 | ||||
-rw-r--r-- | make/scripts/java-win32.bat | 2 | ||||
-rw-r--r-- | make/scripts/make.jogl.all.linux-x86.sh | 1 | ||||
-rw-r--r-- | make/scripts/make.jogl.all.win32.bat | 2 | ||||
-rw-r--r-- | make/scripts/make.jogl.all.win64.bat | 2 | ||||
-rwxr-xr-x | src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java | 9 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/Window.java | 13 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java | 22 | ||||
-rwxr-xr-x | src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java | 30 | ||||
-rwxr-xr-x | src/newt/native/WindowsWindow.c | 84 |
10 files changed, 105 insertions, 62 deletions
diff --git a/make/scripts/java-win32-dbg.bat b/make/scripts/java-win32-dbg.bat index 9d9af8262..13aaee239 100644 --- a/make/scripts/java-win32-dbg.bat +++ b/make/scripts/java-win32-dbg.bat @@ -7,7 +7,7 @@ set ANT_PATH=C:\apache-ant-1.8.0 set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%PATH%
set BLD_DIR=..\%BLD_SUB%
-set LIB_DIR=%BLD_DIR%\lib;..\..\gluegen\%BLD_SUB%\obj
+set LIB_DIR=..\..\gluegen\%BLD_SUB%\obj;%BLD_DIR%\nativewindow\obj;%BLD_DIR%\jogl\obj;%BLD_DIR%\newt\obj
set CP_ALL=.;%BLD_DIR%\jogl\jogl.all.jar;%BLD_DIR%\nativewindow\nativewindow.all.jar;%BLD_DIR%\newt\newt.all.jar;%BLD_DIR%\jogl\jogl.test.jar;..\..\gluegen\%BLD_SUB%\gluegen-rt.jar;..\..\gluegen\make\lib\junit-4.5.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar
diff --git a/make/scripts/java-win32.bat b/make/scripts/java-win32.bat index dade13565..b21d13ba1 100644 --- a/make/scripts/java-win32.bat +++ b/make/scripts/java-win32.bat @@ -7,7 +7,7 @@ set ANT_PATH=C:\apache-ant-1.8.0 set PATH=%JAVA_HOME%\bin;%ANT_PATH%\bin;c:\mingw\bin;%PATH%
set BLD_DIR=..\%BLD_SUB%
-set LIB_DIR=%BLD_DIR%\lib;..\..\gluegen\%BLD_SUB%\obj
+set LIB_DIR=..\..\gluegen\%BLD_SUB%\obj;%BLD_DIR%\nativewindow\obj;%BLD_DIR%\jogl\obj;%BLD_DIR%\newt\obj
set CP_ALL=.;%BLD_DIR%\jogl\jogl.all.jar;%BLD_DIR%\nativewindow\nativewindow.all.jar;%BLD_DIR%\newt\newt.all.jar;%BLD_DIR%\jogl\jogl.test.jar;..\..\gluegen\%BLD_SUB%\gluegen-rt.jar;..\..\gluegen\make\lib\junit-4.5.jar;%ANT_PATH%\lib\ant.jar;%ANT_PATH%\lib\ant-junit.jar
diff --git a/make/scripts/make.jogl.all.linux-x86.sh b/make/scripts/make.jogl.all.linux-x86.sh index d73d3b7f7..5b443f5d3 100644 --- a/make/scripts/make.jogl.all.linux-x86.sh +++ b/make/scripts/make.jogl.all.linux-x86.sh @@ -41,6 +41,7 @@ fi ant \ $CUSTOMLIBDIR \ + -Dbuild.noarchives=true \ -Dgluegen-cpptasks.file=`pwd`/../../gluegen/make/lib/gluegen-cpptasks-linux-32bit.xml \ -Dbuild.noarchives=true \ -Djogl.cg=1 -Dx11.cg.lib=../../lib-linux-x86 \ diff --git a/make/scripts/make.jogl.all.win32.bat b/make/scripts/make.jogl.all.win32.bat index 2638ffbac..ee48fd4bf 100644 --- a/make/scripts/make.jogl.all.win32.bat +++ b/make/scripts/make.jogl.all.win32.bat @@ -14,4 +14,4 @@ REM -DuseKD=true REM -Djogl.cg=1 -D-Dwindows.cg.lib=C:\Cg-2.2
REM -Dbuild.noarchives=true
-ant -Drootrel.build=build-win32 -Djogl.cg=1 -Dwindows.cg.lib=C:\Cg-2.2\lib %1 %2 %3 %4 %5 %6 %7 %8 %9 > make.jogl.all.win32.log 2>&1
+ant -Dbuild.noarchives=true -Drootrel.build=build-win32 -Djogl.cg=1 -Dwindows.cg.lib=C:\Cg-2.2\lib %1 %2 %3 %4 %5 %6 %7 %8 %9 > make.jogl.all.win32.log 2>&1
diff --git a/make/scripts/make.jogl.all.win64.bat b/make/scripts/make.jogl.all.win64.bat index d549866ab..99546f60a 100644 --- a/make/scripts/make.jogl.all.win64.bat +++ b/make/scripts/make.jogl.all.win64.bat @@ -14,4 +14,4 @@ REM -DuseKD=true REM -Djogl.cg=1 -D-Dwindows.cg.lib=C:\Cg-2.2
REM -Dbuild.noarchives=true
-ant -Drootrel.build=build-win64 -Djogl.cg=1 -Dwindows.cg.lib=C:\Cg-2.2\lib %1 %2 %3 %4 %5 %6 %7 %8 %9 > make.jogl.all.win64.log 2>&1
+ant -Dbuild.noarchives=true -Drootrel.build=build-win64 -Djogl.cg=1 -Dwindows.cg.lib=C:\Cg-2.2\lib %1 %2 %3 %4 %5 %6 %7 %8 %9 > make.jogl.all.win64.log 2>&1
diff --git a/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java index 474025835..3d88668ee 100755 --- a/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java +++ b/src/junit/com/jogamp/test/junit/newt/TestParenting01NEWT.java @@ -85,8 +85,6 @@ public class TestParenting01NEWT { Assert.assertNotNull(window); window.setSize(width, height); Assert.assertTrue(false==window.isVisible()); - window.setVisible(true); - Assert.assertTrue(true==window.isVisible()); Assert.assertTrue(width==window.getWidth()); Assert.assertTrue(height==window.getHeight()); System.out.println("Created: "+window); @@ -138,15 +136,20 @@ public class TestParenting01NEWT { Assert.assertNotNull(window1); window1.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - PARENT"); window1.setPosition(x,y); - window1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + // window1.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); GLWindow glWindow1 = GLWindow.create(window1); Assert.assertNotNull(glWindow1); Window window2 = createWindow(window1, screen, caps, width/2, height/2, true /* onscreen */, false /* undecorated */); Assert.assertNotNull(window2); window2.setTitle("testWindowParenting01NewtOnNewtParentChildDraw - CHILD"); + System.out.println("Window1: "+window1); + // Assert.assertTrue(width==window1.getWidth()); + // Assert.assertTrue(height==window1.getHeight()); window2.setPosition(window1.getWidth()/2, window1.getHeight()/2); window2.addKeyListener(new TraceKeyAdapter(new KeyAction(eventFifo))); + // window2.addMouseListener(new TraceMouseAdapter()); + window2.requestFocus(); GLWindow glWindow2 = GLWindow.create(window2); Assert.assertNotNull(glWindow2); diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 653d76522..e807ad6af 100755 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -507,22 +507,31 @@ public abstract class Window implements NativeWindow } public abstract void setVisible(boolean visible); + /** * Sets the size of the client area of the window, excluding decorations * Total size of the window will be - * {@code width+insets.left+insets.right, height+insets.top+insets.bottom} + * {@code width+insets.left+insets.right, height+insets.top+insets.bottom}<br> + * + * This call is ignored if in fullscreen mode.<br> + * * @param width of the client area of the window * @param height of the client area of the window */ public abstract void setSize(int width, int height); + /** * Sets the location of the top left corner of the window, including * decorations (so the client area will be placed at - * {@code x+insets.left,y+insets.top}. + * {@code x+insets.left,y+insets.top}.<br> + * + * This call is ignored if in fullscreen mode.<br> + * * @param x coord of the top left corner * @param y coord of the top left corner */ public abstract void setPosition(int x, int y); + public abstract boolean setFullscreen(boolean fullscreen); // diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java index ce1a0ad2e..bec7bfed2 100755 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java @@ -159,13 +159,13 @@ public class WindowsWindow extends Window { public void setSize(int width, int height) { if (width != this.width || this.height != height) { if(!fullscreen) { + this.width=width; + this.height=height; nfs_width=width; nfs_height=height; - } - this.width = width; - this.height = height; - if(0!=windowHandle && !fullscreen) { - setSize0(parentWindowHandle, windowHandle, x, y, width, height); + if(0!=windowHandle) { + setSize0(parentWindowHandle, windowHandle, x, y, width, height); + } } } } @@ -174,13 +174,13 @@ public class WindowsWindow extends Window { public void setPosition(int x, int y) { if ( this.x != x || this.y != y ) { if(!fullscreen) { + this.x=x; + this.y=y; nfs_x=x; nfs_y=y; - } - this.x = x; - this.y = y; - if(0!=windowHandle && !fullscreen) { - setPosition(parentWindowHandle, windowHandle, x , y); + if(0!=windowHandle) { + setPosition0(parentWindowHandle, windowHandle, x , y /*, width, height*/); + } } } } @@ -245,7 +245,7 @@ public class WindowsWindow extends Window { private native long MonitorFromWindow(long windowHandle); private static native void setVisible0(long windowHandle, boolean visible); private native void setSize0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height); - private native void setPosition(long parentWindowHandle, long windowHandle, int x, int y); + private static native void setPosition0(long parentWindowHandle, long windowHandle, int x, int y /*, int width, int height*/); private native void setFullscreen0(long parentWindowHandle, long windowHandle, int x, int y, int width, int height, boolean isUndecorated, boolean on); private static native void setTitle(long windowHandle, String title); private static native void requestFocus(long windowHandle); diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java index cd089ccfb..2fa41c62a 100755 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java @@ -95,39 +95,29 @@ public class X11Window extends Window { } public void setSize(int width, int height) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window setSize: "+this.x+"/"+this.y+" "+this.width+"x"+this.height+" -> "+width+"x"+height); - // Exception e = new Exception("XXXXXXXXXX"); - // e.printStackTrace(); - } if (width != this.width || this.height != height) { - this.width = width; - this.height = height; if(!fullscreen) { + this.width = width; + this.height = height; nfs_width=width; nfs_height=height; - } - if(0!=windowHandle && !fullscreen) { - setSize0(getDisplayHandle(), windowHandle, width, height); + if(0!=windowHandle) { + setSize0(getDisplayHandle(), windowHandle, width, height); + } } } } public void setPosition(int x, int y) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("X11Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y); - // Exception e = new Exception("XXXXXXXXXX"); - // e.printStackTrace(); - } if ( this.x != x || this.y != y ) { - this.x = x; - this.y = y; if(!fullscreen) { + this.x = x; + this.y = y; nfs_x=x; nfs_y=y; - } - if(0!=windowHandle && !fullscreen) { - setPosition0(parentWindowHandle, getDisplayHandle(), windowHandle, x, y); + if(0!=windowHandle) { + setPosition0(parentWindowHandle, getDisplayHandle(), windowHandle, x, y); + } } } } diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 69b87d39d..647aa75f9 100755 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -99,6 +99,7 @@ #include "NewtCommon.h" // #define VERBOSE_ON 1 +// #define DEBUG_KEYS 1 #ifdef VERBOSE_ON #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) @@ -106,6 +107,8 @@ #define DBG_PRINT(...) #endif +#define STD_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) + static jmethodID sizeChangedID = NULL; static jmethodID insetsChangedID = NULL; static jmethodID positionChangedID = NULL; @@ -592,6 +595,13 @@ static int WmKeyUp(JNIEnv *env, jobject window, UINT wkey, UINT repCnt, return 0; } +static void NewtWindows_requestFocus (HWND hwnd) { + if (IsWindow(hwnd)) { + SetForegroundWindow(hwnd); // Slightly Higher Priority + SetFocus(hwnd);// Sets Keyboard Focus To TheWindow + } +} + static RECT * UpdateInsets(JNIEnv *env, HWND hwnd, jobject window) { // being naughty here @@ -647,8 +657,8 @@ static RECT * UpdateInsets(JNIEnv *env, HWND hwnd, jobject window) } } - DBG_PRINT("*** WindowsWindow: UpdateInsets window %p, %d/%d %dx%d\n", hwnd, - m_insets.left, m_insets.top, m_insets.right-m_insets.left, m_insets.top-m_insets.bottom); + DBG_PRINT("*** WindowsWindow: UpdateInsets window %p, %d/%d %dx%d\n", + (void*)hwnd, (int)m_insets.left, (int)m_insets.top, (int)(m_insets.right-m_insets.left), (int)(m_insets.top-m_insets.bottom)); (*env)->CallVoidMethod(env, window, insetsChangedID, m_insets.left, m_insets.top, @@ -675,6 +685,8 @@ static void WmSize(JNIEnv *env, HWND wnd, jobject window, UINT type) w = rc.right - rc.left; h = rc.bottom - rc.top; + DBG_PRINT("*** WindowsWindow: WmSize window %p, %dx%d\n", (void*)wnd, w, h); + (*env)->CallVoidMethod(env, window, sizeChangedID, w, h); } @@ -687,6 +699,12 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, BOOL isKeyDown = FALSE; WindowUserData * wud; +#ifdef DEBUG_KEYS + if ( WM_KEYDOWN == message ) { + STD_PRINT("*** WindowsWindow: wndProc window %p, 0x%X %d/%d\n", wnd, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); + } +#endif + #if defined(UNDER_CE) || _MSC_VER <= 1200 wud = (WindowUserData *) GetWindowLong(wnd, GWL_USERDATA); #else @@ -739,6 +757,9 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, break; case WM_KEYDOWN: +#ifdef DEBUG_KEYS + STD_PRINT("*** WindowsWindow: windProc sending window %p -> %p, 0x%X %d/%d\n", wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); +#endif useDefWindowProc = WmKeyDown(env, window, wParam, LOWORD(lParam), HIWORD(lParam), FALSE); break; @@ -764,6 +785,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, case WM_LBUTTONDOWN: + NewtWindows_requestFocus ( wnd ); // request focus on this window, if not already .. (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -782,6 +804,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, break; case WM_MBUTTONDOWN: + NewtWindows_requestFocus ( wnd ); // request focus on this window, if not already .. (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -800,6 +823,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, break; case WM_RBUTTONDOWN: + NewtWindows_requestFocus ( wnd ); // request focus on this window, if not already .. (*env)->CallVoidMethod(env, window, sendMouseEventID, (jint) EVENT_MOUSE_PRESSED, GetModifiers(), @@ -909,6 +933,11 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsDisplay_Dispatch gotOne = PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE); if (gotOne) { ++i; +#ifdef DEBUG_KEYS + if(WM_KEYDOWN == msg.message) { + STD_PRINT("*** WindowsWindow: DispatchMessages window %p, 0x%X %d/%d\n", msg.hwnd, msg.message, (int)LOWORD(msg.lParam), (int)HIWORD(msg.lParam)); + } +#endif TranslateMessage(&msg); DispatchMessage(&msg); } @@ -993,7 +1022,7 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getWidthI /* * Class: com_jogamp_newt_impl_windows_WindowsScreen - * Method: getWidthImpl + * Method: getHeightImpl * Signature: (I)I */ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getHeightImpl @@ -1047,7 +1076,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_CreateWi { HWND parentWindow = (HWND) (intptr_t) parent; const TCHAR* wndName = NULL; - DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; + DWORD windowStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_TABSTOP; int x=(int)jx, y=(int)jy; int width=(int)defaultWidth, height=(int)defaultHeight; HWND window = NULL; @@ -1091,6 +1120,11 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_CreateWi UpdateInsets(env, window, obj); ShowWindow(window, SW_SHOWNORMAL); + if(NULL!=parentWindow) { + NewtWindows_requestFocus ( window ); // request focus on this window, if not already .. + } /* else { + // top level already capable of receiving [keyboard] events + } */ } #ifdef UNICODE @@ -1171,7 +1205,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setVisibl /* * Class: com_jogamp_newt_impl_windows_WindowsWindow * Method: setSize0 - * Signature: (JII)V + * Signature: (JIIII)V */ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setSize0 (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y, jint width, jint height) @@ -1195,9 +1229,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setSize0 } DBG_PRINT("*** WindowsWindow: setSize parent %p, window %p, %d/%d %dx%d -> %d/%d %dx%d\n", - hwndP, hwnd, - x, y, width, height, - nX, nY, nWidth, nHeight); + hwndP, hwnd, x, y, width, height, nX, nY, nWidth, nHeight); MoveWindow(hwnd, nX, nY, nWidth, nHeight, TRUE); @@ -1207,23 +1239,34 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setSize0 /* * Class: com_jogamp_newt_impl_windows_WindowsWindow - * Method: setPosition - * Signature: (JII)V + * Method: setPosition0 + * Signature: (JJII)V */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setPosition - (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y) +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setPosition0 + (JNIEnv *env, jclass clazz, jlong parent, jlong window, jint x, jint y/*, jint width, jint height*/) { - UINT flags = SWP_NOACTIVATE | SWP_NOSIZE; HWND hwndP = (HWND) (intptr_t) parent; HWND hwnd = (HWND) (intptr_t) window; if(NULL==hwndP) { - flags |= SWP_NOZORDER; - } + DBG_PRINT("*** WindowsWindow: setPosition.1 parent %p, window %p, %d/%d\n", hwndP, hwnd, x, y); + + // Top Level Window .. SetWindowPos -> no need to do insets .. + SetWindowPos(hwnd, hwndP, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER); + } else { + RECT rc; + int w, h; + + GetClientRect(hwnd, &rc); + w = rc.right - rc.left; + h = rc.bottom - rc.top; - DBG_PRINT("*** WindowsWindow: setPosition parent %p, window %p, %d/%d\n", hwndP, hwnd, x, y); + DBG_PRINT("*** WindowsWindow: setPosition.2 parent %p, window %p, %d/%d, %dx%d\n", + hwndP, hwnd, x, y, /* width, height,*/ w, h); - SetWindowPos(hwnd, hwndP, x, y, 0, 0, flags); + // Child Window .. must use MoveWindow, no insets (no decoration) + MoveWindow(hwnd, x, y, w, h, FALSE); + } } /* @@ -1288,9 +1331,6 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setTitle JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_requestFocus (JNIEnv *env, jclass clazz, jlong window) { - HWND hwnd = (HWND) (intptr_t) window; - - if (IsWindow(hwnd)) { - SetFocus(hwnd); - } + NewtWindows_requestFocus ( (HWND) (intptr_t) window ) ; } + |