mpv/Gui/wm/ws.c

1190 lines
39 KiB
C

// --------------------------------------------------------------------------
// AutoSpace Window System for Linux/Win32 v0.85
// Writed by pontscho/fresh!mindworkz
// --------------------------------------------------------------------------
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include "../../config.h"
#include "ws.h"
#include "wsconv.h"
#include "../../postproc/rgb2rgb.h"
#include <X11/extensions/XShm.h>
#ifdef HAVE_XSHAPE
#include <X11/extensions/shape.h>
#endif
#include <sys/ipc.h>
#include <sys/shm.h>
typedef struct
{
unsigned long flags;
unsigned long functions;
unsigned long decorations;
long input_mode;
unsigned long status;
} MotifWmHints;
Atom wsMotifHints;
int wsMaxX = 0; // Screen width.
int wsMaxY = 0; // Screen height.
Display * wsDisplay;
int wsScreen;
Window wsRootWin;
XEvent wsEvent;
int wsWindowDepth;
GC wsHGC;
MotifWmHints wsMotifWmHints;
Atom wsTextProperlyAtom = None;
int wsDepthOnScreen = 0;
int wsRedMask = 0;
int wsGreenMask = 0;
int wsBlueMask = 0;
int wsOutMask = 0;
int wsTrue = True;
wsTWindow * wsWindowList[5] = { NULL,NULL,NULL,NULL,NULL };
int wsWLCount = 0;
unsigned long wsKeyTable[512];
int wsUseXShm = 1;
int wsUseXShape = 1;
int XShmGetEventBase( Display* );
inline int wsSearch( Window win );
#define MWM_HINTS_FUNCTIONS (1L << 0)
#define MWM_HINTS_DECORATIONS (1L << 1)
#define MWM_HINTS_INPUT_MODE (1L << 2)
#define MWM_HINTS_STATUS (1L << 3)
#define MWM_FUNC_ALL (1L << 0)
#define MWM_FUNC_RESIZE (1L << 1)
#define MWM_FUNC_MOVE (1L << 2)
#define MWM_FUNC_MINIMIZE (1L << 3)
#define MWM_FUNC_MAXIMIZE (1L << 4)
#define MWM_FUNC_CLOSE (1L << 5)
#define MWM_DECOR_ALL (1L << 0)
#define MWM_DECOR_BORDER (1L << 1)
#define MWM_DECOR_RESIZEH (1L << 2)
#define MWM_DECOR_TITLE (1L << 3)
#define MWM_DECOR_MENU (1L << 4)
#define MWM_DECOR_MINIMIZE (1L << 5)
#define MWM_DECOR_MAXIMIZE (1L << 6)
#define MWM_INPUT_MODELESS 0
#define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
#define MWM_INPUT_SYSTEM_MODAL 2
#define MWM_INPUT_FULL_APPLICATION_MODAL 3
#define MWM_INPUT_APPLICATION_MODAL MWM_INPUT_PRIMARY_APPLICATION_MODAL
#define MWM_TEAROFF_WINDOW (1L<<0)
void wsWindowDecoration( wsTWindow * win,long d )
{
wsMotifHints=XInternAtom( wsDisplay,"_MOTIF_WM_HINTS",0 );
if ( wsMotifHints == None ) return;
memset( &wsMotifWmHints,0,sizeof( MotifWmHints ) );
wsMotifWmHints.flags=MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
if ( d )
{
wsMotifWmHints.functions=MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE | MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
wsMotifWmHints.decorations=MWM_DECOR_ALL;
}
XChangeProperty( wsDisplay,win->WindowID,wsMotifHints,wsMotifHints,32,
PropModeReplace,(unsigned char *)&wsMotifWmHints,5 );
}
// ----------------------------------------------------------------------------------------------
// Init X Window System.
// ----------------------------------------------------------------------------------------------
int wsIOErrorHandler( Display * dpy )
{
fprintf( stderr,"[ws] io error in display.\n" );
exit( 0 );
}
int wsErrorHandler( Display * dpy,XErrorEvent * Event )
{
char type[128];
XGetErrorText( wsDisplay,Event->error_code,type,128 );
fprintf(stderr,"[ws] Error in display.\n");
fprintf(stderr,"[ws] Error code: %d ( %s )\n",Event->error_code,type );
fprintf(stderr,"[ws] Request code: %d\n",Event->request_code );
fprintf(stderr,"[ws] Minor code: %d\n",Event->minor_code );
exit( 0 );
}
void wsXInit( void* mDisplay )
{
int eventbase;
int errorbase;
if(mDisplay){
wsDisplay=mDisplay;
} else {
char * DisplayName = ":0.0";
if ( getenv( "DISPLAY" ) ) DisplayName=getenv( "DISPLAY" );
wsDisplay=XOpenDisplay( DisplayName );
if ( !wsDisplay )
{
fprintf( stderr,"[ws] couldn't open the display !\n" );
exit( 0 );
}
}
{ /* on remote display XShm will be disabled - LGB */
char *dispname=DisplayString(wsDisplay);
int localdisp=1;
if (dispname&&*dispname!=':') {
localdisp=0;
wsUseXShm=0;
}
fprintf(stderr,"[ws] Display name: %s => %s display.\n",dispname,localdisp?"local":"REMOTE");
if (!localdisp) fprintf(stderr,"[ws] Remote display, disabling XMITSHM\n");
}
if ( !XShmQueryExtension( wsDisplay ) )
{
fprintf( stderr,"[ws] sorry, your system is not supported X shared memory extension.\n" );
wsUseXShm=0;
}
#ifdef HAVE_XSHAPE
if ( !XShapeQueryExtension( wsDisplay,&eventbase,&errorbase ) )
{
fprintf( stderr,"[ws] sorry, your system is not supported XShape extension.\n" );
wsUseXShape=0;
}
#else
wsUseXShape=0;
#endif
XSynchronize( wsDisplay,True );
wsScreen=DefaultScreen( wsDisplay );
wsRootWin=RootWindow( wsDisplay,wsScreen );
wsMaxX=DisplayWidth( wsDisplay,wsScreen );
wsMaxY=DisplayHeight( wsDisplay,wsScreen );
wsGetDepthOnScreen();
#ifdef DEBUG
{
int minor,major,shp;
fprintf( stderr,"[ws] Screen depth: %d\n",wsDepthOnScreen );
fprintf( stderr,"[ws] size: %dx%d\n",wsMaxX,wsMaxY );
fprintf( stderr,"[ws] red mask: 0x%x\n",wsRedMask );
fprintf( stderr,"[ws] green mask: 0x%x\n",wsGreenMask );
fprintf( stderr,"[ws] blue mask: 0x%x\n",wsBlueMask );
if ( wsUseXShm )
{
XShmQueryVersion( wsDisplay,&major,&minor,&shp );
fprintf( stderr,"[ws] XShm version is %d.%d\n",major,minor );
}
#ifdef HAVE_XSHAPE
if ( wsUseXShape )
{
XShapeQueryVersion( wsDisplay,&major,&minor );
fprintf( stderr,"[ws] XShape version is %d.%d\n",major,minor );
}
#endif
}
#endif
initConverter();
wsOutMask=wsGetOutMask();
#ifdef DEBUG
fprintf( stderr,"[ws] Initialized converter: " );
#endif
switch ( wsOutMask )
{
case wsRGB32:
#ifdef DEBUG
fprintf( stderr,"rgb32 to rgb32\n" );
#endif
wsConvFunc=BGR8880_to_RGB8880_c;
break;
case wsBGR32:
#ifdef DEBUG
fprintf( stderr,"rgb32 to bgr32\n" );
#endif
// wsConvFunc=BGR8880_to_BGR8880_c;
wsConvFunc=rgb32tobgr32;
break;
case wsRGB24:
#ifdef DEBUG
fprintf( stderr,"rgb32 to rgb24\n" );
#endif
wsConvFunc=rgb32to24;
break;
case wsBGR24:
#ifdef DEBUG
fprintf( stderr,"rgb32 to bgr24\n" );
#endif
wsConvFunc=BGR8880_to_BGR888_c;
break;
case wsRGB16:
#ifdef DEBUG
fprintf( stderr,"rgb32 to rgb16\n" );
#endif
wsConvFunc=rgb32to16;
break;
case wsBGR16:
#ifdef DEBUG
fprintf( stderr,"rgb32 to bgr16\n" );
#endif
wsConvFunc=BGR8880_to_BGR565_c;
break;
case wsRGB15:
#ifdef DEBUG
fprintf( stderr,"rgb32 to rgb15\n" );
#endif
wsConvFunc=rgb32to15;
break;
case wsBGR15:
#ifdef DEBUG
fprintf( stderr,"rgb32 to bgr15\n" );
#endif
wsConvFunc=BGR8880_to_BGR555_c;
break;
}
// XSetIOErrorHandler( wsIOErrorHandler );
// XSetErrorHandler( wsErrorHandler );
}
// ----------------------------------------------------------------------------------------------
// Create window.
// X,Y : window position
// wX,wY : size of window
// bW : border width
// cV : visible mouse cursor on window
// D : visible frame, title, etc.
// sR : screen ratio
// ----------------------------------------------------------------------------------------------
XClassHint wsClassHint;
XTextProperty wsTextProperty;
Window LeaderWindow;
void wsCreateWindow( wsTWindow * win,int X,int Y,int wX,int hY,int bW,int cV,unsigned char D,char * label )
{
win->Property=D;
if ( D & wsShowFrame ) win->Decorations=1;
wsHGC=DefaultGC( wsDisplay,wsScreen );
// The window position and size.
switch ( X )
{
case -1: win->X=( wsMaxX / 2 ) - ( wX / 2 ); break;
case -2: win->X=wsMaxX - wX - 1; break;
default: win->X=X; break;
}
switch ( Y )
{
case -1: win->Y=( wsMaxY / 2 ) - ( hY / 2 ); break;
case -2: win->Y=wsMaxY - hY - 1; break;
default: win->Y=Y; break;
}
win->Width=wX;
win->Height=hY;
win->OldX=win->X;
win->OldY=win->Y;
win->OldWidth=win->Width;
win->OldHeight=win->Height;
// Border size for window.
win->BorderWidth=bW;
// Hide Mouse Cursor
win->wsCursor=None;
win->wsMouseEventType=cV;
win->wsCursorData[0]=0;
win->wsCursorPixmap=XCreateBitmapFromData( wsDisplay,wsRootWin,win->wsCursorData,1,1 );
if ( !(cV & wsShowMouseCursor) ) win->wsCursor=XCreatePixmapCursor( wsDisplay,win->wsCursorPixmap,win->wsCursorPixmap,&win->wsColor,&win->wsColor,0,0 );
XGetWindowAttributes( wsDisplay,wsRootWin,&win->Attribs );
if ( win->Attribs.depth < 15 )
{
fprintf( stderr,"[ws] sorry, this color depth is not enough.\n" );
exit( 0 );
}
XMatchVisualInfo( wsDisplay,wsScreen,win->Attribs.depth,TrueColor,&win->VisualInfo );
// ---
win->AtomLeaderClient=XInternAtom( wsDisplay,"WM_CLIENT_LEADER",False );
win->AtomDeleteWindow=XInternAtom( wsDisplay,"WM_DELETE_WINDOW",False );
win->AtomTakeFocus=XInternAtom( wsDisplay,"WM_TAKE_FOCUS",False );
win->AtomRolle=XInternAtom( wsDisplay,"WM_WINDOW_ROLE",False );
win->AtomWMSizeHint=XInternAtom( wsDisplay,"WM_SIZE_HINT",False );
win->AtomWMNormalHint=XInternAtom( wsDisplay,"WM_NORMAL_HINT",False );
win->AtomProtocols=XInternAtom( wsDisplay,"WM_PROTOCOLS",False );
{
char buf[32]; int i;
sprintf( buf,"_%s_REMOTE",label );
for( i=0;i < (int)strlen( buf );i++ )
if ( ( buf[i] >= 'a' )&&( buf[i] <= 'z' ) ) buf[i]=buf[i] - 32;
for( i=0;i < (int)strlen( buf );i++ )
if ( buf[i] == ' ' ) buf[i]='_';
fprintf( stderr,"[ws] atomname: %s\n",buf );
win->AtomRemote=XInternAtom( wsDisplay,buf,False );
}
win->AtomsProtocols[0]=win->AtomDeleteWindow;
win->AtomsProtocols[1]=win->AtomTakeFocus;
win->AtomsProtocols[2]=win->AtomRolle;
// ---
// win->WindowAttrib.background_pixel=BlackPixel( wsDisplay,wsScreen );
// win->WindowAttrib.border_pixel=BlackPixel( wsDisplay,wsScreen );
win->WindowAttrib.background_pixel=BlackPixel( wsDisplay,wsScreen );
win->WindowAttrib.border_pixel=WhitePixel( wsDisplay,wsScreen );
win->WindowAttrib.colormap=XCreateColormap( wsDisplay,wsRootWin,win->VisualInfo.visual,AllocNone );
win->WindowAttrib.event_mask=StructureNotifyMask | FocusChangeMask |
//SubstructureRedirectMask |
//SubstructureNotifyMask |
//ResizeRedirectMask |
//GCGraphicsExposures |
ExposureMask | PropertyChangeMask |
EnterWindowMask | LeaveWindowMask |
VisibilityChangeMask |
KeyPressMask | KeyReleaseMask;
if ( ( cV & wsHandleMouseButton ) ) win->WindowAttrib.event_mask|=ButtonPressMask | ButtonReleaseMask;
if ( ( cV & wsHandleMouseMove ) ) win->WindowAttrib.event_mask|=PointerMotionMask;
win->WindowAttrib.cursor=win->wsCursor;
win->WindowAttrib.override_redirect=False;
if ( D & wsOverredirect ) win->WindowAttrib.override_redirect=True;
// win->WindowAttrib.save_under=True;
// win->WindowAttrib.do_not_propagate_mask = True;
win->WindowMask=CWBackPixel | CWBorderPixel |
CWColormap | CWEventMask | CWCursor |
CWX | CWY | CWWidth | CWHeight |
CWOverrideRedirect;
win->WindowID=XCreateWindow( wsDisplay,
(win->Parent != 0?win->Parent:wsRootWin),
win->X,win->Y,win->Width,win->Height,win->BorderWidth,
win->VisualInfo.depth,
InputOutput,
win->VisualInfo.visual,
win->WindowMask,&win->WindowAttrib );
#if 0
wsClassHint.res_name=label;
#else
wsClassHint.res_name="MPlayer";
#endif
wsClassHint.res_class="MPlayer";
XSetClassHint( wsDisplay,win->WindowID,&wsClassHint );
win->SizeHint.flags=PPosition | PSize | PResizeInc | PWinGravity; // | PBaseSize
win->SizeHint.x=win->X;
win->SizeHint.y=win->Y;
win->SizeHint.width=win->Width;
win->SizeHint.height=win->Height;
if ( D & wsMinSize )
{
win->SizeHint.flags|=PMinSize;
win->SizeHint.min_width=win->Width;
win->SizeHint.min_height=win->Height;
}
if ( D & wsMaxSize )
{
win->SizeHint.flags|=PMaxSize;
win->SizeHint.max_width=win->Width;
win->SizeHint.max_height=win->Height;
}
win->SizeHint.height_inc=1;
win->SizeHint.width_inc=1;
// win->SizeHint.base_width=win->Width;
// win->SizeHint.base_height=win->Height;
win->SizeHint.win_gravity=StaticGravity;
XSetWMNormalHints( wsDisplay,win->WindowID,&win->SizeHint );
win->WMHints.flags=InputHint | StateHint;
win->WMHints.input=True;
win->WMHints.initial_state=NormalState;
XSetWMHints( wsDisplay,win->WindowID,&win->WMHints );
wsWindowDecoration( win,win->Decorations );
XStoreName( wsDisplay,win->WindowID,label );
XmbSetWMProperties( wsDisplay,win->WindowID,label,label,NULL,0,NULL,NULL,NULL );
XSetWMProtocols( wsDisplay,win->WindowID,win->AtomsProtocols,3 );
XChangeProperty( wsDisplay,win->WindowID,
win->AtomLeaderClient,
XA_WINDOW,32,PropModeReplace,
(unsigned char *)&LeaderWindow,1 );
wsTextProperty.value=label;
wsTextProperty.encoding=XA_STRING;
wsTextProperty.format=8;
wsTextProperty.nitems=strlen( label );
XSetWMIconName( wsDisplay,win->WindowID,&wsTextProperty );
XChangeProperty( wsDisplay,win->WindowID,
win->AtomRemote,XA_STRING,
8,PropModeReplace,
"REALIZED",8 );
// win->Font=XLoadQueryFont( wsDisplay,"-adobe-helvetica-bold-r-normal--14-140-75-75-p-77-iso8859-1" );
// -adobe-times-medium-r-normal--14-140-75-75-p-77-iso8859-1" );
// -misc-fixed-bold-r-normal--13-120-75-75-C-80-iso8859-1" );
// -misc-fixed-bold-r-normal--15-140-75-75-C-90-iso8859-1" );
// -misc-fixed-medium-r-normal--15-140-75-75-C-90-iso8859-1" );
// -adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1" );
// -adobe-helvetica-medium-r-normal--10-100-75-75-p-56-iso8859-1" );
// -*-helvetica-bold-o-normal--14-*-*-*-p-*-iso8859-1" );
// if ( !win->Font ) win->Font=XLoadQueryFont( wsDisplay,"fixed" );
// if ( !win->Font )
// {
// fprintf( stderr,"[main] could not load font.\n" );
// exit( 0 );
// }
// win->FontHeight=win->Font->ascent + win->Font->descent;
//
// #ifdef DEBUG
// fprintf( stderr,"[ws] font height: %d\n",win->FontHeight );
// #endif
// win->wGCV.font=win->Font->fid;
// win->wGCV.foreground=wsBlack;
// win->wGCV.background=wsBlack;
win->wGC=XCreateGC( wsDisplay,win->WindowID,
GCForeground | GCBackground,
&win->wGCV );
win->Visible=0;
win->Focused=0;
win->Mapped=0;
win->Rolled=0;
if ( D & wsShowWindow ) XMapWindow( wsDisplay,win->WindowID );
wsCreateImage( win,win->Width,win->Height );
// --- End of creating --------------------------------------------------------------------------
wsWindowList[wsWLCount++]=win;
XFlush( wsDisplay );
XSync( wsDisplay,False );
win->ReDraw=NULL;
win->ReSize=NULL;
win->Idle=NULL;
win->MouseHandler=NULL;
win->KeyHandler=NULL;
#ifdef DEBUG
fprintf( stderr,"[ws] window is created. ( %s ).\n",label );
#endif
}
void wsDestroyWindow( wsTWindow * win )
{
int l;
l=wsSearch( win->WindowID );
wsWindowList[l]=NULL;
if ( win->wsCursor != None )
{
XFreeCursor( wsDisplay,win->wsCursor );
win->wsCursor=None;
}
XUnmapWindow( wsDisplay,win->WindowID );
wsDestroyImage( win );
XDestroyWindow( wsDisplay,win->WindowID );
win->ReDraw=NULL;
win->ReSize=NULL;
win->Idle=NULL;
win->MouseHandler=NULL;
win->KeyHandler=NULL;
win->Visible=0;
win->Focused=0;
win->Mapped=0;
win->Rolled=0;
}
// ----------------------------------------------------------------------------------------------
// Handle events.
// ----------------------------------------------------------------------------------------------
inline int wsSearch( Window win )
{
int i;
for ( i=0;i<wsWLCount;i++ ) if ( wsWindowList[i]->WindowID == win ) return i;
return -1;
}
Bool wsEvents( Display * display,XEvent * Event,XPointer arg )
{
KeySym keySym;
unsigned long i = 0;
int l;
int x,y;
Window child_window = 0;
l=wsSearch( Event->xany.window );
if ( l == -1 ) return !wsTrue;
wsWindowList[l]->State=0;
switch( Event->type )
{
case ClientMessage:
if ( Event->xclient.message_type == wsWindowList[l]->AtomProtocols )
{
if ( Event->xclient.data.l[0] == wsWindowList[l]->AtomDeleteWindow )
{ wsTrue=False; break; }
if ( Event->xclient.data.l[0] == wsWindowList[l]->AtomTakeFocus )
{ i=wsWindowFocusIn; wsWindowList[l]->Focused=wsFocused; goto expose; }
if ( Event->xclient.data.l[0] == wsWindowList[l]->AtomRolle )
{ fprintf( stderr,"[ws] rolled.\n" ); }
}
break;
// case CirculateRequest:fprintf( stderr,"[ws,r] win: 0x%x\n",(int)Event->xcirculaterequest.window ); break;
// case CirculateNotify: fprintf( stderr,"[ws,c] win: 0x%x\n",(int)Event->xcirculate.window ); break;
case MapNotify: i=wsWindowMapped; wsWindowList[l]->Mapped=wsMapped; goto expose;
case UnmapNotify: i=wsWindowUnmapped; wsWindowList[l]->Mapped=wsNone; goto expose;
case FocusIn:
if ( wsWindowList[l]->Focused == wsFocused ) break;
i=wsWindowFocusIn;
wsWindowList[l]->Focused=wsFocused;
goto expose;
case FocusOut:
if ( wsWindowList[l]->Focused == wsNone ) break;
i=wsWindowFocusOut;
wsWindowList[l]->Focused=wsNone;
goto expose;
case VisibilityNotify:
switch( Event->xvisibility.state )
{
case VisibilityUnobscured: i=wsWindowVisible; wsWindowList[l]->Visible=wsVisible; goto expose;
case VisibilityFullyObscured: i=wsWindowNotVisible; wsWindowList[l]->Visible=wsNotVisible; goto expose;
case VisibilityPartiallyObscured: i=wsWindowPartialVisible; wsWindowList[l]->Visible=wsPVisible; goto expose;
}
expose:
wsWindowList[l]->State=i;
if ( wsWindowList[l]->ReDraw ) wsWindowList[l]->ReDraw( wsDisplay,Event->xany.window );
break;
case Expose:
wsWindowList[l]->State=wsWindowExpose;
if ( ( wsWindowList[l]->ReDraw )&&( !Event->xexpose.count ) ) wsWindowList[l]->ReDraw( wsDisplay,Event->xany.window );
break;
case ConfigureNotify:
XTranslateCoordinates( wsDisplay,wsWindowList[l]->WindowID,wsRootWin,0,0,&x,&y,&child_window );
if ( ( wsWindowList[l]->X != x )||( wsWindowList[l]->Y != y )||( wsWindowList[l]->Width != Event->xconfigure.width )||( wsWindowList[l]->Height != Event->xconfigure.height ) )
{
wsWindowList[l]->X=x; wsWindowList[l]->Y=y;
wsWindowList[l]->Width=Event->xconfigure.width; wsWindowList[l]->Height=Event->xconfigure.height;
// fprintf( stderr,"[ws] resize: %d,%d %dx%d\n",wsWindowList[l]->X,wsWindowList[l]->Y,Event->xconfigure.width,Event->xconfigure.height );
if ( wsWindowList[l]->ReSize ) wsWindowList[l]->ReSize( wsWindowList[l]->X,wsWindowList[l]->Y,wsWindowList[l]->Width,wsWindowList[l]->Height );
}
wsWindowList[l]->Rolled=wsNone;
if ( Event->xconfigure.y < 0 )
{ i=wsWindowRolled; wsWindowList[l]->Rolled=wsRolled; goto expose; }
break;
case KeyPress: i=wsKeyPressed; goto keypressed;
case KeyRelease: i=wsKeyReleased;
keypressed:
wsWindowList[l]->Alt=0;
wsWindowList[l]->Shift=0;
wsWindowList[l]->NumLock=0;
wsWindowList[l]->Control=0;
wsWindowList[l]->CapsLock=0;
if ( Event->xkey.state & Mod1Mask ) wsWindowList[l]->Alt=1;
if ( Event->xkey.state & Mod2Mask ) wsWindowList[l]->NumLock=1;
if ( Event->xkey.state & ControlMask ) wsWindowList[l]->Control=1;
if ( Event->xkey.state & ShiftMask ) wsWindowList[l]->Shift=1;
if ( Event->xkey.state & LockMask ) wsWindowList[l]->CapsLock=1;
keySym=XKeycodeToKeysym( wsDisplay,Event->xkey.keycode,0 );
if ( keySym != NoSymbol )
{
keySym=( (keySym&0xff00) != 0?( (keySym&0x00ff) + 256 ):( keySym ) );
wsKeyTable[ keySym ]=i;
if ( wsWindowList[l]->KeyHandler )
wsWindowList[l]->KeyHandler( Event->xkey.state,i,keySym );
}
break;
case MotionNotify: i=wsMoveMouse; goto buttonreleased;
case ButtonRelease: i=Event->xbutton.button + 128; goto buttonreleased;
case ButtonPress: i=Event->xbutton.button; goto buttonreleased;
case EnterNotify: i=wsEnterWindow; goto buttonreleased;
case LeaveNotify: i=wsLeaveWindow;
buttonreleased:
if ( wsWindowList[l]->MouseHandler )
wsWindowList[l]->MouseHandler( i,Event->xbutton.x,Event->xbutton.y,Event->xmotion.x_root,Event->xmotion.y_root );
break;
// case GravityNotify:
// #ifdef DEBUG
// fprintf( stderr,"[ws] window ( 0x%x ) gravity: %d,%d\n",wsWindowList[l]->WindowID,Event->xgravity.x,Event->xgravity.y );
// #endif
// break;
case PropertyNotify:
// break;
// #ifdef DEBUG
// fprintf(stderr,"[ws] PropertyNotify ( 0x%x ) %s ( 0x%x )\n",wsWindowList[l]->WindowID,XGetAtomName( wsDisplay,Event->xproperty.atom ),Event->xproperty.atom );
// #endif
if ( Event->xproperty.atom == wsWindowList[l]->AtomRemote )
{
Atom type;
int format;
unsigned long nitems, bytesafter;
unsigned char * args = NULL;
// fprintf( stderr,"[ws] remote property notify.\n" );
XGetWindowProperty( wsDisplay,
Event->xproperty.window,
Event->xproperty.atom,
0,( 65536 / sizeof( long ) ),
False,XA_STRING,
&type,&format,&nitems,&bytesafter,
&args );
if ( ( nitems )&&( wsWindowList[l]->RemoteHandler ) )
{
args[strlen( args ) - 1]=0;
wsWindowList[l]->RemoteHandler( args );
#ifdef DEBUG
fprintf( stderr,"[ws] args: '%s'\n",args );
#endif
args[strlen( args ) - 1]=1;
XFree( args );
}
}
break;
}
XFlush( wsDisplay );
XSync( wsDisplay,False );
return !wsTrue;
// return True;
}
Bool wsDummyEvents( Display * display,XEvent * Event,XPointer arg )
{ return True; }
void wsHandleEvents( void ){
// handle pending events
while ( XPending(wsDisplay) ){
XNextEvent( wsDisplay,&wsEvent );
// printf("### X event: %d [%d]\n",wsEvent.type,delay);
wsEvents( wsDisplay,&wsEvent,NULL );
}
}
extern void mplTimerHandler( void );
void wsMainLoop( void )
{
int delay=20;
fprintf( stderr,"[ws] init threads: %d\n",XInitThreads() );
XSynchronize( wsDisplay,False );
XLockDisplay( wsDisplay );
// XIfEvent( wsDisplay,&wsEvent,wsEvents,NULL );
#if 1
while(wsTrue){
// handle pending events
while ( XPending(wsDisplay) ){
XNextEvent( wsDisplay,&wsEvent );
// printf("### X event: %d [%d]\n",wsEvent.type,delay);
wsEvents( wsDisplay,&wsEvent,NULL );
delay=0;
}
mplTimerHandler(); // handle timer event
usleep(delay*1000); // FIXME!
if(delay<10*20) delay+=20; // pump up delay up to 0.2 sec (low activity)
}
#else
while( wsTrue )
{
XIfEvent( wsDisplay,&wsEvent,wsDummyEvents,NULL );
wsEvents( wsDisplay,&wsEvent,NULL );
}
#endif
XUnlockDisplay( wsDisplay );
}
// ----------------------------------------------------------------------------------------------
// Switch to fullscreen.
// ----------------------------------------------------------------------------------------------
void wsFullScreen( wsTWindow * win )
{
int decoration = 0;
XUnmapWindow( wsDisplay,win->WindowID );
win->SizeHint.flags=0;
if ( win->isFullScreen )
{
win->X=win->OldX;
win->Y=win->OldY;
win->Width=win->OldWidth;
win->Height=win->OldHeight;
win->isFullScreen=False;
decoration=win->Decorations;
wsScreenSaverOn( wsDisplay );
}
else
{
win->OldX=win->X; win->OldY=win->Y;
win->OldWidth=win->Width; win->OldHeight=win->Height;
win->X=0; win->Y=0;
win->Width=wsMaxX; win->Height=wsMaxY;
win->isFullScreen=True;
wsScreenSaverOff( wsDisplay );
}
win->SizeHint.flags|=PPosition | PSize;
win->SizeHint.x=win->X;
win->SizeHint.y=win->Y;
win->SizeHint.width=win->Width;
win->SizeHint.height=win->Height;
if ( win->Property & wsMaxSize )
{
win->SizeHint.flags|=PMaxSize;
win->SizeHint.max_width=win->Width;
win->SizeHint.max_height=win->Height;
}
if ( win->Property & wsMinSize )
{
win->SizeHint.flags|=PMinSize;
win->SizeHint.min_width=win->Width;
win->SizeHint.min_height=win->Height;
}
XSetWMNormalHints( wsDisplay,win->WindowID,&win->SizeHint );
XMoveResizeWindow( wsDisplay,win->WindowID,win->X,win->Y,win->Width,win->Height );
wsWindowDecoration( win,decoration );
XRaiseWindow( wsDisplay,win->WindowID );
XMapWindow( wsDisplay,win->WindowID );
}
// ----------------------------------------------------------------------------------------------
// Redraw screen.
// ----------------------------------------------------------------------------------------------
void wsPostRedisplay( wsTWindow * win )
{
if ( win->ReDraw )
{
win->ReDraw( wsDisplay,win->WindowID );
XFlush( wsDisplay );
}
}
// ----------------------------------------------------------------------------------------------
// Do Exit.
// ----------------------------------------------------------------------------------------------
void wsDoExit( void )
{ wsTrue=False; wsResizeWindow( wsWindowList[0],32,32 ); }
// ----------------------------------------------------------------------------------------------
// Put 'Image' to window.
// ----------------------------------------------------------------------------------------------
void wsConvert( wsTWindow * win,unsigned char * Image,unsigned int Size )
{ if ( wsConvFunc ) wsConvFunc( Image,win->ImageData,win->xImage->width * win->xImage->height * 4 ); }
void wsPutImage( wsTWindow * win )
{
if ( wsUseXShm )
{
XShmPutImage( wsDisplay,win->WindowID,win->wGC,win->xImage,
0,0,
( win->Width - win->xImage->width ) / 2,( win->Height - win->xImage->height ) / 2,
win->xImage->width,win->xImage->height,0 );
// win->Width,win->Height,0 );
}
else
{
XPutImage( wsDisplay,win->WindowID,win->wGC,win->xImage,
0,0,
( win->Width - win->xImage->width ) / 2,( win->Height - win->xImage->height ) / 2,
win->xImage->width,win->xImage->height );
}
}
// ----------------------------------------------------------------------------------------------
// Move window to x, y.
// ----------------------------------------------------------------------------------------------
void wsMoveWindow( wsTWindow * win,int b,int x, int y )
{
if ( b )
{
switch ( x )
{
case -1: win->X=( wsMaxX / 2 ) - ( win->Width / 2 ); break;
case -2: win->X=wsMaxX - win->Width; break;
default: win->X=x; break;
}
switch ( y )
{
case -1: win->Y=( wsMaxY / 2 ) - ( win->Height / 2 ); break;
case -2: win->Y=wsMaxY - win->Height; break;
default: win->Y=y; break;
}
}
else { win->X=x; win->Y=y; }
win->SizeHint.flags=PPosition | PWinGravity;
win->SizeHint.x=win->X;
win->SizeHint.y=win->Y;
win->SizeHint.win_gravity=StaticGravity;
XSetWMNormalHints( wsDisplay,win->WindowID,&win->SizeHint );
XMoveWindow( wsDisplay,win->WindowID,win->X,win->Y );
if ( win->ReSize ) win->ReSize( win->X,win->Y,win->Width,win->Height );
}
// ----------------------------------------------------------------------------------------------
// Resize window to sx, sy.
// ----------------------------------------------------------------------------------------------
void wsResizeWindow( wsTWindow * win,int sx, int sy )
{
win->Width=sx;
win->Height=sy;
win->SizeHint.flags=PSize | PWinGravity;
win->SizeHint.width=win->Width;
win->SizeHint.height=win->Height;
if ( win->Property & wsMinSize )
{
win->SizeHint.flags|=PMinSize;
win->SizeHint.min_width=win->Width;
win->SizeHint.min_height=win->Height;
}
if ( win->Property & wsMaxSize )
{
win->SizeHint.flags|=PMaxSize;
win->SizeHint.max_width=win->Width;
win->SizeHint.max_height=win->Height;
}
win->SizeHint.win_gravity=StaticGravity;
XSetWMNormalHints( wsDisplay,win->WindowID,&win->SizeHint );
XResizeWindow( wsDisplay,win->WindowID,sx,sy );
if ( win->ReSize ) win->ReSize( win->X,win->Y,win->Width,win->Height );
}
// ----------------------------------------------------------------------------------------------
// Iconify window.
// ----------------------------------------------------------------------------------------------
void wsIconify( wsTWindow win )
{ XIconifyWindow( wsDisplay,win.WindowID,0 ); }
// ----------------------------------------------------------------------------------------------
// Move top the window.
// ----------------------------------------------------------------------------------------------
void wsMoveTopWindow( wsTWindow * win )
{
// XUnmapWindow( wsDisplay,win->WindowID ); XMapWindow( wsDisplay,win->WindowID );
XRaiseWindow( wsDisplay,win->WindowID );
}
// ----------------------------------------------------------------------------------------------
// Set window background to 'color'.
// ----------------------------------------------------------------------------------------------
void wsSetBackground( wsTWindow * win,int color )
{ XSetWindowBackground( wsDisplay,win->WindowID,color ); }
void wsSetBackgroundRGB( wsTWindow * win,int r,int g,int b )
{
int color = 0;
switch ( wsOutMask )
{
case wsRGB32:
case wsRGB24: color=( r << 16 ) + ( g << 8 ) + b; break;
case wsBGR32:
case wsBGR24: color=( b << 16 ) + ( g << 8 ) + r; break;
case wsRGB16: PACK_RGB16( b,g,r,color ); break;
case wsBGR16: PACK_RGB16( r,g,b,color ); break;
case wsRGB15: PACK_RGB15( b,g,r,color ); break;
case wsBGR15: PACK_RGB15( r,g,b,color ); break;
}
XSetWindowBackground( wsDisplay,win->WindowID,color );
}
void wsSetForegroundRGB( wsTWindow * win,int r,int g,int b )
{
int color = 0;
switch ( wsOutMask )
{
case wsRGB32:
case wsRGB24: color=( r << 16 ) + ( g << 8 ) + b; break;
case wsBGR32:
case wsBGR24: color=( b << 16 ) + ( g << 8 ) + r; break;
case wsRGB16: PACK_RGB16( b,g,r,color ); break;
case wsBGR16: PACK_RGB16( r,g,b,color ); break;
case wsRGB15: PACK_RGB15( b,g,r,color ); break;
case wsBGR15: PACK_RGB15( r,g,b,color ); break;
}
XSetForeground( wsDisplay,win->wGC,color );
}
// ----------------------------------------------------------------------------------------------
// Draw string at x,y with fc ( foreground color ) and bc ( background color ).
// ----------------------------------------------------------------------------------------------
void wsDrawString( wsTWindow win,int x,int y,char * str,int fc,int bc )
{
XSetForeground( wsDisplay,win.wGC,bc );
XFillRectangle( wsDisplay,win.WindowID,win.wGC,x,y,
XTextWidth( win.Font,str,strlen( str ) ) + 20,
win.FontHeight + 2 );
XSetForeground( wsDisplay,win.wGC,fc );
XDrawString( wsDisplay,win.WindowID,win.wGC,x + 10,y + 13,str,strlen( str ) );
}
// ----------------------------------------------------------------------------------------------
// Calculation string width.
// ----------------------------------------------------------------------------------------------
int wsTextWidth( wsTWindow win,char * str )
{ return XTextWidth( win.Font,str,strlen( str ) ) + 20; }
// ----------------------------------------------------------------------------------------------
// Show / hide mouse cursor.
// ----------------------------------------------------------------------------------------------
void wsVisibleMouse( wsTWindow * win,int m )
{
switch ( m )
{
case wsShowMouseCursor:
if ( win->wsCursor != None )
{
XFreeCursor( wsDisplay,win->wsCursor );
win->wsCursor=None;
}
XDefineCursor( wsDisplay,win->WindowID,0 );
break;
case wsHideMouseCursor:
win->wsCursor=XCreatePixmapCursor( wsDisplay,win->wsCursorPixmap,win->wsCursorPixmap,&win->wsColor,&win->wsColor,0,0 );
XDefineCursor( wsDisplay,win->WindowID,win->wsCursor );
break;
}
XFlush( wsDisplay );
}
int wsGetDepthOnScreen( void )
{
int bpp,ibpp;
XImage * mXImage;
XWindowAttributes attribs;
mXImage=XGetImage( wsDisplay,wsRootWin,0,0,1,1,AllPlanes,ZPixmap );
bpp=mXImage->bits_per_pixel;
XGetWindowAttributes( wsDisplay,wsRootWin,&attribs );
ibpp=attribs.depth;
mXImage=XGetImage( wsDisplay,wsRootWin,0,0,1,1,AllPlanes,ZPixmap );
bpp=mXImage->bits_per_pixel;
if ( ( ibpp + 7 ) / 8 != ( bpp + 7 ) / 8 ) ibpp=bpp;
wsDepthOnScreen=ibpp;
wsRedMask=mXImage->red_mask;
wsGreenMask=mXImage->green_mask;
wsBlueMask=mXImage->blue_mask;
XDestroyImage( mXImage );
return ibpp;
}
void wsXDone( void )
{
XCloseDisplay( wsDisplay );
}
void wsVisibleWindow( wsTWindow * win,int show )
{
switch( show )
{
case wsShowWindow: XMapWindow( wsDisplay,win->WindowID ); break;
case wsHideWindow: XUnmapWindow( wsDisplay,win->WindowID ); break;
}
XFlush( wsDisplay );
}
void wsDestroyImage( wsTWindow * win )
{
if ( win->xImage )
{
XDestroyImage( win->xImage );
if ( wsUseXShm )
{
XShmDetach( wsDisplay,&win->Shminfo );
shmdt( win->Shminfo.shmaddr );
}
}
win->xImage=NULL;
}
void wsCreateImage( wsTWindow * win,int Width,int Height )
{
int CompletionType = -1;
if ( wsUseXShm )
{
CompletionType=XShmGetEventBase( wsDisplay ) + ShmCompletion;
win->xImage=XShmCreateImage( wsDisplay,win->VisualInfo.visual,
win->Attribs.depth,ZPixmap,NULL,&win->Shminfo,Width,Height );
if ( win->xImage == NULL )
{
fprintf( stderr,"[ws] shared memory extension error.\n" );
exit( 0 );
}
// #ifdef DEBUG
// fprintf( stderr,"[ws] Screen depth: %d\n",win->xImage->bits_per_pixel );
// #endif
win->Shminfo.shmid=shmget( IPC_PRIVATE,win->xImage->bytes_per_line * win->xImage->height,IPC_CREAT|0777 );
if ( win->Shminfo.shmid < 0 )
{
XDestroyImage( win->xImage );
fprintf( stderr,"[ws] shared memory extension error.\n" );
exit( 0 );
}
win->Shminfo.shmaddr=(char *)shmat( win->Shminfo.shmid,0,0 );
if ( win->Shminfo.shmaddr == ((char *) -1) )
{
XDestroyImage( win->xImage );
if ( win->Shminfo.shmaddr != ((char *) -1) ) shmdt( win->Shminfo.shmaddr );
fprintf( stderr,"[ws] shared memory extension error.\n" );
exit( 0 );
}
win->xImage->data=win->Shminfo.shmaddr;
win->Shminfo.readOnly=0;
XShmAttach( wsDisplay,&win->Shminfo );
shmctl( win->Shminfo.shmid,IPC_RMID,0 );
}
else
{
win->xImage=XCreateImage( wsDisplay,win->VisualInfo.visual,win->Attribs.depth,
ZPixmap,0,0,Width,Height,
(wsDepthOnScreen == 3) ? 32 : wsDepthOnScreen,
0 );
if ( ( win->xImage->data=malloc( win->xImage->bytes_per_line * win->xImage->height ) ) == NULL )
{
fprintf( stderr,"[ws] sorry, not enough memory for draw buffer.\n" );
exit( 0 );
}
}
win->ImageData=(unsigned char *)win->xImage->data;
win->ImageDataw=(unsigned short int *)win->xImage->data;
win->ImageDatadw=(unsigned int *)win->xImage->data;
}
void wsResizeImage( wsTWindow * win,int Width,int Height )
{ wsDestroyImage( win ); wsCreateImage( win,Width,Height ); }
int wsGetOutMask( void )
{
if ( ( wsDepthOnScreen == 32 )&&( wsRedMask == 0xff0000 )&&( wsGreenMask == 0x00ff00 )&&( wsBlueMask == 0x0000ff ) ) return wsRGB32;
if ( ( wsDepthOnScreen == 32 )&&( wsRedMask == 0x0000ff )&&( wsGreenMask == 0x00ff00 )&&( wsBlueMask == 0xff0000 ) ) return wsBGR32;
if ( ( wsDepthOnScreen == 24 )&&( wsRedMask == 0xff0000 )&&( wsGreenMask == 0x00ff00 )&&( wsBlueMask == 0x0000ff ) ) return wsRGB24;
if ( ( wsDepthOnScreen == 24 )&&( wsRedMask == 0x0000ff )&&( wsGreenMask == 0x00ff00 )&&( wsBlueMask == 0xff0000 ) ) return wsBGR24;
if ( ( wsDepthOnScreen == 16 )&&( wsRedMask == 0xf800 )&&( wsGreenMask == 0x7e0 )&&( wsBlueMask == 0x1f ) ) return wsRGB16;
if ( ( wsDepthOnScreen == 16 )&&( wsRedMask == 0x1f )&&( wsGreenMask == 0x7e0 )&&( wsBlueMask == 0xf800 ) ) return wsBGR16;
if ( ( wsDepthOnScreen == 15 )&&( wsRedMask == 0x7c00 )&&( wsGreenMask == 0x3e0 )&&( wsBlueMask == 0x1f ) ) return wsRGB15;
if ( ( wsDepthOnScreen == 15 )&&( wsRedMask == 0x1f )&&( wsGreenMask == 0x3e0 )&&( wsBlueMask == 0x7c00 ) ) return wsBGR15;
return 0;
}
void wsSetTitle( wsTWindow * win,char * name )
{ XStoreName( wsDisplay,win->WindowID,name ); }
void wsSetMousePosition( wsTWindow * win,int x, int y )
{ XWarpPointer( wsDisplay,wsRootWin,win->WindowID,0,0,0,0,x,y ); }
static int dpms_disabled=0;
static int timeout_save=0;
void wsScreenSaverOn( Display *mDisplay )
{
int nothing;
#ifdef HAVE_XDPMS
if ( dpms_disabled )
{
if ( DPMSQueryExtension( mDisplay,&nothing,&nothing ) )
{
if ( !DPMSEnable( mDisplay ) ) fprintf( stderr,"DPMS not available ?\n" ); // restoring power saving settings
else
{
// DPMS does not seem to be enabled unless we call DPMSInfo
BOOL onoff;
CARD16 state;
DPMSInfo( mDisplay,&state,&onoff );
if ( onoff ) fprintf( stderr,"Successfully enabled DPMS.\n" );
else fprintf( stderr,"Could not enable DPMS.\n" );
}
}
}
#endif
if ( timeout_save )
{
int dummy, interval, prefer_blank, allow_exp;
XGetScreenSaver( mDisplay,&dummy,&interval,&prefer_blank,&allow_exp );
XSetScreenSaver( mDisplay,timeout_save,interval,prefer_blank,allow_exp );
XGetScreenSaver( mDisplay,&timeout_save,&interval,&prefer_blank,&allow_exp );
}
}
void wsScreenSaverOff( Display * mDisplay )
{
int interval,prefer_blank,allow_exp,nothing;
#ifdef HAVE_XDPMS
if ( DPMSQueryExtension( mDisplay,&nothing,&nothing ) )
{
BOOL onoff;
CARD16 state;
DPMSInfo( mDisplay,&state,&onoff );
if ( onoff )
{
Status stat;
fprintf( stderr,"Disabling DPMS.\n" );
dpms_disabled=1;
stat=DPMSDisable( mDisplay ); // monitor powersave off
fprintf( stderr,"stat: %d.\n",stat );
}
}
#endif
XGetScreenSaver( mDisplay,&timeout_save,&interval,&prefer_blank,&allow_exp );
if ( timeout_save ) XSetScreenSaver( mDisplay,0,interval,prefer_blank,allow_exp ); // turning off screensaver
}
void wsSetShape( wsTWindow * win,char * data )
{
#ifdef HAVE_XSHAPE
if ( !wsUseXShape ) return;
if ( data )
{
win->Mask=XCreateBitmapFromData( wsDisplay,win->WindowID,data,win->Width,win->Height );
XShapeCombineMask( wsDisplay,win->WindowID,ShapeBounding,0,0,win->Mask,ShapeSet );
XFreePixmap( wsDisplay,win->Mask );
}
else XShapeCombineMask( wsDisplay,win->WindowID,ShapeBounding,0,0,None,ShapeSet );
#endif
}
#include "wsmkeys.h"