Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
ea0fd4d5
Commit
ea0fd4d5
authored
Sep 23, 1999
by
Noel Borthwick
Committed by
Alexandre Julliard
Sep 23, 1999
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added clipboard server.
parent
37fd2d1c
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
995 additions
and
0 deletions
+995
-0
Makefile.in
Makefile.in
+2
-0
.cvsignore
windows/x11drv/.cvsignore
+1
-0
Makefile.in
windows/x11drv/Makefile.in
+7
-0
wineclipsrv.c
windows/x11drv/wineclipsrv.c
+985
-0
No files found.
Makefile.in
View file @
ea0fd4d5
...
...
@@ -258,6 +258,8 @@ install_lib: dummy
$(INSTALL_DATA)
$(LIB_TARGET)
$(libdir)
;
\
if
[
$(LIB_TARGET)
=
libwine.so.1.0
]
;
then
$(LDCONFIG)
;
fi
\
fi
[
-d
$(bindir)
]
||
$(MKDIR)
$(bindir)
$(INSTALL_PROGRAM)
windows/x11drv/wineclipsrv
$(bindir)
/wineclipsrv
uninstall_lib
:
dummy
cd
$(libdir)
;
$(RM)
$(LIB_TARGET)
libwine.a libwine.so wine.sym
...
...
windows/x11drv/.cvsignore
View file @
ea0fd4d5
Makefile
wineclipsrv
windows/x11drv/Makefile.in
View file @
ea0fd4d5
...
...
@@ -16,6 +16,13 @@ C_SRCS = \
mouse.c
\
wnd.c
PROGRAMS
=
wineclipsrv
all
:
$(MODULE).o $(PROGRAMS)
wineclipsrv
:
wineclipsrv.c
$(CC)
$(ALLCFLAGS)
-o
wineclipsrv
$(SRCDIR)
/wineclipsrv.c
$(X_LIBS)
$(XLIB)
$(LIBS)
all
:
$(MODULE).o
@MAKE_RULES@
...
...
windows/x11drv/wineclipsrv.c
0 → 100644
View file @
ea0fd4d5
/*
* Wine Clipboard Server
*
* Copyright 1999 Noel Borthwick
*
* NOTES:
* This file contains the implementation for the Clipboard server
*
* TODO:
*
*/
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Xatom.h>
#include <stdio.h>
/* Lightweight debug definitions */
#define __DPRINTF(dbname) (printf("%s:%s:%s ", dbname, progname, __FUNCTION__),0) ? 0 : printf
#define __DUMMY_DPRINTF 1 ? (void)0 : (void)((int (*)(char *, ...)) NULL)
#ifndef NO_TRACE_MSGS
#define TRACE __DPRINTF("TRACE")
#else
#define TRACE __DUMMY_DPRINTF
#endif
/* NO_TRACE_MSGS */
#ifndef NO_DEBUG_MSGS
#define WARN __DPRINTF("WARN")
#define FIXME __DPRINTF("FIXME")
#else
#define WARN __DUMMY_DPRINTF
#define FIXME __DUMMY_DPRINTF
#endif
/* NO_DEBUG_MSGS */
#define ERR __DPRINTF("ERROR")
#define TRUE 1
#define FALSE 0
typedef
int
BOOL
;
/* Selection masks */
#define S_NOSELECTION 0
#define S_PRIMARY 1
#define S_CLIPBOARD 2
/*
* Global variables
*/
static
Display
*
g_display
=
NULL
;
static
int
screen_num
;
static
char
*
progname
;
/* name this program was invoked by */
static
Window
g_win
=
0
;
/* the hidden clipboard server window */
static
GC
g_gc
=
0
;
static
char
*
g_szOutOfMemory
=
"Insufficient memory!
\n
"
;
/* X selection context info */
static
char
_CLIPBOARD
[]
=
"CLIPBOARD"
;
/* CLIPBOARD atom name */
static
char
FMT_PREFIX
[]
=
"<WCF>"
;
/* Prefix for windows specific formats */
static
int
g_selectionToAcquire
=
0
;
/* Masks for the selection to be acquired */
static
int
g_selectionAcquired
=
0
;
/* Contains the current selection masks */
/* Selection cache */
typedef
struct
tag_CACHEENTRY
{
Atom
target
;
Atom
type
;
int
nFormat
;
int
nElements
;
void
*
pData
;
}
CACHEENTRY
,
*
PCACHEENTRY
;
static
PCACHEENTRY
g_pPrimaryCache
=
NULL
;
/* Primary selection cache */
static
PCACHEENTRY
g_pClipboardCache
=
NULL
;
/* Clipboard selection cache */
static
unsigned
long
g_cPrimaryTargets
=
0
;
/* Number of TARGETS reported by PRIMARY selection */
static
unsigned
long
g_cClipboardTargets
=
0
;
/* Number of TARGETS reported by CLIPBOARD selection */
/* Event names */
static
const
char
*
const
event_names
[]
=
{
""
,
""
,
"KeyPress"
,
"KeyRelease"
,
"ButtonPress"
,
"ButtonRelease"
,
"MotionNotify"
,
"EnterNotify"
,
"LeaveNotify"
,
"FocusIn"
,
"FocusOut"
,
"KeymapNotify"
,
"Expose"
,
"GraphicsExpose"
,
"NoExpose"
,
"VisibilityNotify"
,
"CreateNotify"
,
"DestroyNotify"
,
"UnmapNotify"
,
"MapNotify"
,
"MapRequest"
,
"ReparentNotify"
,
"ConfigureNotify"
,
"ConfigureRequest"
,
"GravityNotify"
,
"ResizeRequest"
,
"CirculateNotify"
,
"CirculateRequest"
,
"PropertyNotify"
,
"SelectionClear"
,
"SelectionRequest"
,
"SelectionNotify"
,
"ColormapNotify"
,
"ClientMessage"
,
"MappingNotify"
};
/*
* Prototypes
*/
BOOL
Init
(
int
argc
,
char
**
argv
);
void
TerminateServer
(
int
ret
);
int
AcquireSelection
();
int
CacheDataFormats
(
Atom
SelectionSrc
,
PCACHEENTRY
*
ppCache
);
void
EmptyCache
(
PCACHEENTRY
pCache
,
int
nItems
);
BOOL
FillCacheEntry
(
Atom
SelectionSrc
,
Atom
target
,
PCACHEENTRY
pCacheEntry
);
BOOL
LookupCacheItem
(
Atom
selection
,
Atom
target
,
PCACHEENTRY
*
ppCacheEntry
);
void
EVENT_ProcessEvent
(
XEvent
*
event
);
Atom
EVENT_SelectionRequest_MULTIPLE
(
XSelectionRequestEvent
*
pevent
);
void
EVENT_SelectionRequest
(
XSelectionRequestEvent
*
event
,
BOOL
bIsMultiple
);
void
EVENT_SelectionClear
(
XSelectionClearEvent
*
event
);
void
EVENT_PropertyNotify
(
XPropertyEvent
*
event
);
Pixmap
DuplicatePixmap
(
Pixmap
pixmap
);
void
TextOut
(
Window
win
,
GC
gc
,
char
*
pStr
);
void
getGC
(
Window
win
,
GC
*
gc
);
void
main
(
int
argc
,
char
**
argv
)
{
XEvent
event
;
unsigned
int
width
,
height
;
/* window size */
if
(
!
Init
(
argc
,
argv
)
)
exit
(
0
);
/* Acquire the selection after retrieving all clipboard data
* owned by the current selection owner. If we were unable to
* Acquire any selection, terminate right away.
*/
if
(
AcquireSelection
()
==
S_NOSELECTION
)
TerminateServer
(
0
);
/* Start an X event loop */
while
(
1
)
{
XNextEvent
(
g_display
,
&
event
);
EVENT_ProcessEvent
(
&
event
);
}
}
/**************************************************************************
* Init()
* Initialize the clipboard server
*/
BOOL
Init
(
int
argc
,
char
**
argv
)
{
unsigned
int
width
,
height
;
/* window size */
unsigned
int
border_width
=
4
;
/* four pixels */
unsigned
int
display_width
,
display_height
;
char
*
window_name
=
"Wine Clipboard Server"
;
XSizeHints
*
size_hints
=
NULL
;
XWMHints
*
wm_hints
=
NULL
;
XClassHint
*
class_hints
=
NULL
;
XTextProperty
windowName
;
char
*
display_name
=
NULL
;
progname
=
argv
[
0
];
if
(
!
(
size_hints
=
XAllocSizeHints
()))
{
ERR
(
g_szOutOfMemory
);
return
0
;
}
if
(
!
(
wm_hints
=
XAllocWMHints
()))
{
ERR
(
g_szOutOfMemory
);
return
0
;
}
if
(
!
(
class_hints
=
XAllocClassHint
()))
{
ERR
(
g_szOutOfMemory
);
return
0
;
}
/* connect to X server */
if
(
(
g_display
=
XOpenDisplay
(
display_name
))
==
NULL
)
{
ERR
(
"cannot connect to X server %s
\n
"
,
XDisplayName
(
display_name
));
return
0
;
}
/* get screen size from display structure macro */
screen_num
=
DefaultScreen
(
g_display
);
display_width
=
DisplayWidth
(
g_display
,
screen_num
);
display_height
=
DisplayHeight
(
g_display
,
screen_num
);
/* size window with enough room for text */
width
=
display_width
/
3
,
height
=
display_height
/
4
;
/* create opaque window */
g_win
=
XCreateSimpleWindow
(
g_display
,
RootWindow
(
g_display
,
screen_num
),
0
,
0
,
width
,
height
,
border_width
,
BlackPixel
(
g_display
,
screen_num
),
WhitePixel
(
g_display
,
screen_num
));
/* Set size hints for window manager. The window manager may
* override these settings. */
/* x, y, width, and height hints are now taken from
* the actual settings of the window when mapped. Note
* that PPosition and PSize must be specified anyway. */
size_hints
->
flags
=
PPosition
|
PSize
|
PMinSize
;
size_hints
->
min_width
=
300
;
size_hints
->
min_height
=
200
;
/* These calls store window_name into XTextProperty structures
* and sets the other fields properly. */
if
(
XStringListToTextProperty
(
&
window_name
,
1
,
&
windowName
)
==
0
)
{
ERR
(
"structure allocation for windowName failed.
\n
"
);
TerminateServer
(
-
1
);
}
wm_hints
->
initial_state
=
NormalState
;
wm_hints
->
input
=
True
;
wm_hints
->
flags
=
StateHint
|
InputHint
;
class_hints
->
res_name
=
progname
;
class_hints
->
res_class
=
"WineClipSrv"
;
XSetWMProperties
(
g_display
,
g_win
,
&
windowName
,
NULL
,
argv
,
argc
,
size_hints
,
wm_hints
,
class_hints
);
/* Select event types wanted */
XSelectInput
(
g_display
,
g_win
,
ExposureMask
|
KeyPressMask
|
ButtonPressMask
|
StructureNotifyMask
|
PropertyChangeMask
);
/* create GC for text and drawing */
getGC
(
g_win
,
&
g_gc
);
/* Display window */
/* XMapWindow(g_display, g_win); */
/* Set the selections to be acquired from the command line argument.
* If none specified, default to all selections we understand.
*/
if
(
argc
>
1
)
g_selectionToAcquire
=
atoi
(
argv
[
1
]);
else
g_selectionToAcquire
=
S_PRIMARY
|
S_CLIPBOARD
;
TRACE
(
"Clipboard server running...
\n
"
);
}
/**************************************************************************
* TerminateServer()
*/
void
TerminateServer
(
int
ret
)
{
TRACE
(
"Terminating Wine clipboard server...
\n
"
);
/* Free Primary and Clipboard selection caches */
EmptyCache
(
g_pPrimaryCache
,
g_cPrimaryTargets
);
EmptyCache
(
g_pClipboardCache
,
g_cClipboardTargets
);
if
(
g_gc
)
XFreeGC
(
g_display
,
g_gc
);
if
(
g_display
)
XCloseDisplay
(
g_display
);
exit
(
ret
);
}
/**************************************************************************
* AcquireSelection()
*
* Acquire the selection after retrieving all clipboard data owned by
* the current selection owner.
*/
int
AcquireSelection
()
{
Atom
xaClipboard
=
XInternAtom
(
g_display
,
_CLIPBOARD
,
False
);
/*
* For all selections we need to acquire, get a list of all targets
* supplied by the current selection owner.
*/
if
(
g_selectionToAcquire
&
S_PRIMARY
)
{
TRACE
(
"Acquiring PRIMARY selection...
\n
"
);
g_cPrimaryTargets
=
CacheDataFormats
(
XA_PRIMARY
,
&
g_pPrimaryCache
);
if
(
g_cPrimaryTargets
)
XSetSelectionOwner
(
g_display
,
XA_PRIMARY
,
g_win
,
CurrentTime
);
else
TRACE
(
"No PRIMARY targets - ownership not acquired.
\n
"
);
}
if
(
g_selectionToAcquire
&
S_CLIPBOARD
)
{
TRACE
(
"Acquiring CLIPBOARD selection...
\n
"
);
g_cClipboardTargets
=
CacheDataFormats
(
xaClipboard
,
&
g_pClipboardCache
);
if
(
g_cClipboardTargets
)
XSetSelectionOwner
(
g_display
,
xaClipboard
,
g_win
,
CurrentTime
);
else
TRACE
(
"No CLIPBOARD targets - ownership not acquired.
\n
"
);
}
/* Remember the acquired selections */
if
(
XGetSelectionOwner
(
g_display
,
XA_PRIMARY
)
==
g_win
)
g_selectionAcquired
|=
S_PRIMARY
;
if
(
XGetSelectionOwner
(
g_display
,
xaClipboard
)
==
g_win
)
g_selectionAcquired
|=
S_CLIPBOARD
;
return
g_selectionAcquired
;
}
/**************************************************************************
* CacheDataFormats
*
* Allocates and caches the list of data formats available from the current selection.
* This queries the selection owner for the TARGETS property and saves all
* reported property types.
*/
int
CacheDataFormats
(
Atom
SelectionSrc
,
PCACHEENTRY
*
ppCache
)
{
XEvent
xe
;
Atom
aTargets
;
Atom
atype
=
AnyPropertyType
;
int
aformat
;
unsigned
long
remain
;
unsigned
long
cSelectionTargets
=
0
;
Atom
*
targetList
=
NULL
;
Window
ownerSelection
=
0
;
if
(
!
ppCache
)
return
0
;
*
ppCache
=
NULL
;
/* Get the selection owner */
ownerSelection
=
XGetSelectionOwner
(
g_display
,
SelectionSrc
);
if
(
ownerSelection
==
None
)
return
cSelectionTargets
;
/*
* Query the selection owner for the TARGETS property
*/
aTargets
=
XInternAtom
(
g_display
,
"TARGETS"
,
False
);
TRACE
(
"Requesting TARGETS selection for '%s' (owner=%08x)...
\n
"
,
XGetAtomName
(
g_display
,
SelectionSrc
),
(
unsigned
)
ownerSelection
);
XConvertSelection
(
g_display
,
SelectionSrc
,
aTargets
,
XInternAtom
(
g_display
,
"SELECTION_DATA"
,
False
),
g_win
,
CurrentTime
);
/*
* Wait until SelectionNotify is received
*/
while
(
TRUE
)
{
if
(
XCheckTypedWindowEvent
(
g_display
,
g_win
,
SelectionNotify
,
&
xe
)
)
if
(
xe
.
xselection
.
selection
==
SelectionSrc
)
break
;
}
/* Verify that the selection returned a valid TARGETS property */
if
(
(
xe
.
xselection
.
target
!=
aTargets
)
||
(
xe
.
xselection
.
property
==
None
)
)
{
TRACE
(
"
\t
Could not retrieve TARGETS
\n
"
);
return
cSelectionTargets
;
}
/* Read the TARGETS property contents */
if
(
XGetWindowProperty
(
g_display
,
xe
.
xselection
.
requestor
,
xe
.
xselection
.
property
,
0
,
0x3FFF
,
True
,
AnyPropertyType
/*XA_ATOM*/
,
&
atype
,
&
aformat
,
&
cSelectionTargets
,
&
remain
,
(
unsigned
char
**
)
&
targetList
)
!=
Success
)
TRACE
(
"
\t
Couldn't read TARGETS property
\n
"
);
else
{
TRACE
(
"
\t
Type %s,Format %d,nItems %ld, Remain %ld
\n
"
,
XGetAtomName
(
g_display
,
atype
),
aformat
,
cSelectionTargets
,
remain
);
/*
* The TARGETS property should have returned us a list of atoms
* corresponding to each selection target format supported.
*/
if
(
(
atype
==
XA_ATOM
||
atype
==
aTargets
)
&&
aformat
==
32
)
{
int
i
;
/* Allocate the selection cache */
*
ppCache
=
(
PCACHEENTRY
)
calloc
(
cSelectionTargets
,
sizeof
(
CACHEENTRY
));
/* Cache these formats in the selection cache */
for
(
i
=
0
;
i
<
cSelectionTargets
;
i
++
)
{
char
*
itemFmtName
=
XGetAtomName
(
g_display
,
targetList
[
i
]);
TRACE
(
"
\t
Atom# %d: '%s'
\n
"
,
i
,
itemFmtName
);
/* Populate the cache entry */
if
(
!
FillCacheEntry
(
SelectionSrc
,
targetList
[
i
],
&
((
*
ppCache
)[
i
])))
ERR
(
"Failed to fill cache entry!"
);
XFree
(
itemFmtName
);
}
}
/* Free the list of targets */
XFree
(
targetList
);
}
return
cSelectionTargets
;
}
/***********************************************************************
* FillCacheEntry
*
* Populates the specified cache entry
*/
BOOL
FillCacheEntry
(
Atom
SelectionSrc
,
Atom
target
,
PCACHEENTRY
pCacheEntry
)
{
XEvent
xe
;
Window
w
;
Atom
prop
,
reqType
;
Atom
atype
=
AnyPropertyType
;
int
aformat
;
unsigned
long
nitems
,
remain
,
itemSize
;
long
lRequestLength
;
unsigned
char
*
val
=
NULL
;
BOOL
bRet
=
FALSE
;
TRACE
(
"Requesting %s selection from %s...
\n
"
,
XGetAtomName
(
g_display
,
target
),
XGetAtomName
(
g_display
,
SelectionSrc
)
);
/* Ask the selection owner to convert the selection to the target format */
XConvertSelection
(
g_display
,
SelectionSrc
,
target
,
XInternAtom
(
g_display
,
"SELECTION_DATA"
,
False
),
g_win
,
CurrentTime
);
/* wait until SelectionNotify is received */
while
(
TRUE
)
{
if
(
XCheckTypedWindowEvent
(
g_display
,
g_win
,
SelectionNotify
,
&
xe
)
)
if
(
xe
.
xselection
.
selection
==
SelectionSrc
)
break
;
}
/* Now proceed to retrieve the actual converted property from
* the SELECTION_DATA atom */
w
=
xe
.
xselection
.
requestor
;
prop
=
xe
.
xselection
.
property
;
reqType
=
xe
.
xselection
.
target
;
if
(
prop
==
None
)
return
bRet
;
TRACE
(
"
\t
retrieving property %s from window %ld into %s
\n
"
,
XGetAtomName
(
g_display
,
reqType
),
(
long
)
w
,
XGetAtomName
(
g_display
,
prop
)
);
/*
* First request a zero length in order to figure out the request size.
*/
if
(
XGetWindowProperty
(
g_display
,
w
,
prop
,
0
,
0
,
False
,
AnyPropertyType
/*reqType*/
,
&
atype
,
&
aformat
,
&
nitems
,
&
itemSize
,
&
val
)
!=
Success
)
{
WARN
(
"
\t
couldn't get property size
\n
"
);
return
bRet
;
}
/* Free zero length return data if any */
if
(
val
)
{
XFree
(
val
);
val
=
NULL
;
}
TRACE
(
"
\t
retrieving %ld bytes...
\n
"
,
itemSize
*
aformat
/
8
);
lRequestLength
=
(
itemSize
*
aformat
/
8
)
/
4
+
1
;
/*
* Retrieve the actual property in the required X format.
*/
if
(
XGetWindowProperty
(
g_display
,
w
,
prop
,
0
,
lRequestLength
,
False
,
AnyPropertyType
/*reqType*/
,
&
atype
,
&
aformat
,
&
nitems
,
&
remain
,
&
val
)
!=
Success
)
{
WARN
(
"
\t
couldn't read property
\n
"
);
return
bRet
;
}
TRACE
(
"
\t
Type %s,Format %d,nitems %ld,remain %ld,value %s
\n
"
,
atype
?
XGetAtomName
(
g_display
,
atype
)
:
NULL
,
aformat
,
nitems
,
remain
,
val
);
if
(
remain
)
{
WARN
(
"
\t
Couldn't read entire property- selection may be too large! Remain=%ld
\n
"
,
remain
);
goto
END
;
}
/*
* Populate the cache entry
*/
pCacheEntry
->
target
=
target
;
pCacheEntry
->
type
=
atype
;
pCacheEntry
->
nFormat
=
aformat
;
pCacheEntry
->
nElements
=
nitems
;
if
(
atype
==
XA_PIXMAP
)
{
Pixmap
*
pPixmap
=
(
Pixmap
*
)
val
;
Pixmap
newPixmap
=
DuplicatePixmap
(
*
pPixmap
);
pPixmap
=
(
Pixmap
*
)
calloc
(
1
,
sizeof
(
Pixmap
));
*
pPixmap
=
newPixmap
;
pCacheEntry
->
pData
=
pPixmap
;
}
else
pCacheEntry
->
pData
=
val
;
END:
/* Delete the property on the window now that we are done
* This will send a PropertyNotify event to the selection owner. */
XDeleteProperty
(
g_display
,
w
,
prop
);
return
TRUE
;
}
/***********************************************************************
* LookupCacheItem
*
* Lookup a target atom in the cache and get the matching cache entry
*/
BOOL
LookupCacheItem
(
Atom
selection
,
Atom
target
,
PCACHEENTRY
*
ppCacheEntry
)
{
int
i
;
int
nCachetargets
=
0
;
PCACHEENTRY
pCache
=
NULL
;
Atom
xaClipboard
=
XInternAtom
(
g_display
,
_CLIPBOARD
,
False
);
/* Locate the cache to be used based on the selection type */
if
(
selection
==
XA_PRIMARY
)
{
pCache
=
g_pPrimaryCache
;
nCachetargets
=
g_cPrimaryTargets
;
}
else
if
(
selection
==
xaClipboard
)
{
pCache
=
g_pClipboardCache
;
nCachetargets
=
g_cClipboardTargets
;
}
if
(
!
pCache
||
!
ppCacheEntry
)
return
FALSE
;
*
ppCacheEntry
=
NULL
;
/* Look for the target item in the cache */
for
(
i
=
0
;
i
<
nCachetargets
;
i
++
)
{
if
(
pCache
[
i
].
target
==
target
)
{
*
ppCacheEntry
=
&
pCache
[
i
];
return
TRUE
;
}
}
return
FALSE
;
}
/***********************************************************************
* EmptyCache
*
* Empties the specified cache
*/
void
EmptyCache
(
PCACHEENTRY
pCache
,
int
nItems
)
{
int
i
;
if
(
!
pCache
)
return
;
/* Release all items in the cache */
for
(
i
=
0
;
i
<
nItems
;
i
++
)
{
if
(
pCache
[
i
].
target
&&
pCache
[
i
].
pData
)
{
/* If we have a Pixmap, free it first */
if
(
pCache
[
i
].
target
==
XA_PIXMAP
||
pCache
[
i
].
target
==
XA_BITMAP
)
{
Pixmap
*
pPixmap
=
(
Pixmap
*
)
pCache
[
i
].
pData
;
TRACE
(
"Freeing %s (handle=%ld)...
\n
"
,
XGetAtomName
(
g_display
,
pCache
[
i
].
target
),
*
pPixmap
);
XFreePixmap
(
g_display
,
*
pPixmap
);
/* Free the cached data item (allocated by us) */
free
(
pCache
[
i
].
pData
);
}
else
{
TRACE
(
"Freeing %s (0x%x)...
\n
"
,
XGetAtomName
(
g_display
,
pCache
[
i
].
target
),
pCache
[
i
].
pData
);
/* Free the cached data item (allocated by X) */
XFree
(
pCache
[
i
].
pData
);
}
}
}
/* Destroy the cache */
free
(
pCache
);
}
/***********************************************************************
* EVENT_ProcessEvent
*
* Process an X event.
*/
void
EVENT_ProcessEvent
(
XEvent
*
event
)
{
// TRACE(" event %s for Window %08lx\n", event_names[event->type], event->xany.window );
switch
(
event
->
type
)
{
case
Expose
:
/* don't draw the window */
if
(
event
->
xexpose
.
count
!=
0
)
break
;
/* Output something */
TextOut
(
g_win
,
g_gc
,
"Click here to terminate"
);
break
;
case
ConfigureNotify
:
break
;
case
ButtonPress
:
/* fall into KeyPress (no break) */
case
KeyPress
:
TerminateServer
(
1
);
break
;
case
SelectionRequest
:
EVENT_SelectionRequest
(
(
XSelectionRequestEvent
*
)
event
,
FALSE
);
break
;
case
SelectionClear
:
EVENT_SelectionClear
(
(
XSelectionClearEvent
*
)
event
);
break
;
case
PropertyNotify
:
EVENT_PropertyNotify
(
(
XPropertyEvent
*
)
event
);
break
;
default:
/* ignore all other events */
break
;
}
/* end switch */
}
/***********************************************************************
* EVENT_SelectionRequest_MULTIPLE
* Service a MULTIPLE selection request event
* rprop contains a list of (target,property) atom pairs.
* The first atom names a target and the second names a property.
* The effect is as if we have received a sequence of SelectionRequest events
* (one for each atom pair) except that:
* 1. We reply with a SelectionNotify only when all the requested conversions
* have been performed.
* 2. If we fail to convert the target named by an atom in the MULTIPLE property,
* we replace the atom in the property by None.
*/
Atom
EVENT_SelectionRequest_MULTIPLE
(
XSelectionRequestEvent
*
pevent
)
{
Atom
rprop
;
Atom
atype
=
AnyPropertyType
;
int
aformat
;
unsigned
long
remain
;
Atom
*
targetPropList
=
NULL
;
unsigned
long
cTargetPropList
=
0
;
/* Atom xAtomPair = XInternAtom(g_display, "ATOM_PAIR", False); */
/* If the specified property is None the requestor is an obsolete client.
* We support these by using the specified target atom as the reply property.
*/
rprop
=
pevent
->
property
;
if
(
rprop
==
None
)
rprop
=
pevent
->
target
;
if
(
!
rprop
)
goto
END
;
/* Read the MULTIPLE property contents. This should contain a list of
* (target,property) atom pairs.
*/
if
(
XGetWindowProperty
(
g_display
,
pevent
->
requestor
,
rprop
,
0
,
0x3FFF
,
False
,
AnyPropertyType
,
&
atype
,
&
aformat
,
&
cTargetPropList
,
&
remain
,
(
unsigned
char
**
)
&
targetPropList
)
!=
Success
)
TRACE
(
"
\t
Couldn't read MULTIPLE property
\n
"
);
else
{
TRACE
(
"
\t
Type %s,Format %d,nItems %ld, Remain %ld
\n
"
,
XGetAtomName
(
g_display
,
atype
),
aformat
,
cTargetPropList
,
remain
);
/*
* Make sure we got what we expect.
* NOTE: According to the X-ICCCM Version 2.0 documentation the property sent
* in a MULTIPLE selection request should be of type ATOM_PAIR.
* However some X apps(such as XPaint) are not compliant with this and return
* a user defined atom in atype when XGetWindowProperty is called.
* The data *is* an atom pair but is not denoted as such.
*/
if
(
aformat
==
32
/* atype == xAtomPair */
)
{
int
i
;
/* Iterate through the ATOM_PAIR list and execute a SelectionRequest
* for each (target,property) pair */
for
(
i
=
0
;
i
<
cTargetPropList
;
i
+=
2
)
{
char
*
targetName
=
XGetAtomName
(
g_display
,
targetPropList
[
i
]);
char
*
propName
=
XGetAtomName
(
g_display
,
targetPropList
[
i
+
1
]);
XSelectionRequestEvent
event
;
TRACE
(
"MULTIPLE(%d): Target='%s' Prop='%s'
\n
"
,
i
/
2
,
targetName
,
propName
);
XFree
(
targetName
);
XFree
(
propName
);
/* We must have a non "None" property to service a MULTIPLE target atom */
if
(
!
targetPropList
[
i
+
1
]
)
{
TRACE
(
"
\t
MULTIPLE(%d): Skipping target with empty property!"
,
i
);
continue
;
}
/* Set up an XSelectionRequestEvent for this (target,property) pair */
memcpy
(
&
event
,
pevent
,
sizeof
(
XSelectionRequestEvent
)
);
event
.
target
=
targetPropList
[
i
];
event
.
property
=
targetPropList
[
i
+
1
];
/* Fire a SelectionRequest, informing the handler that we are processing
* a MULTIPLE selection request event.
*/
EVENT_SelectionRequest
(
&
event
,
TRUE
);
}
}
/* Free the list of targets/properties */
XFree
(
targetPropList
);
}
END:
return
rprop
;
}
/***********************************************************************
* EVENT_SelectionRequest
* Process an event selection request event.
* The bIsMultiple flag is used to signal when EVENT_SelectionRequest is called
* recursively while servicing a "MULTIPLE" selection target.
*
*/
void
EVENT_SelectionRequest
(
XSelectionRequestEvent
*
event
,
BOOL
bIsMultiple
)
{
XSelectionEvent
result
;
Atom
rprop
=
None
;
Window
request
=
event
->
requestor
;
BOOL
couldOpen
=
FALSE
;
Atom
xaMultiple
=
XInternAtom
(
g_display
,
"MULTIPLE"
,
False
);
PCACHEENTRY
pCacheEntry
=
NULL
;
void
*
pData
=
NULL
;
Pixmap
pixmap
;
/* If the specified property is None the requestor is an obsolete client.
* We support these by using the specified target atom as the reply property.
*/
rprop
=
event
->
property
;
if
(
rprop
==
None
)
rprop
=
event
->
target
;
TRACE
(
"Request for %s in selection %s
\n
"
,
XGetAtomName
(
g_display
,
event
->
target
),
XGetAtomName
(
g_display
,
event
->
selection
));
/* Handle MULTIPLE requests - rprop contains a list of (target, property) atom pairs */
if
(
event
->
target
==
xaMultiple
)
{
/* MULTIPLE selection request - will call us back recursively */
rprop
=
EVENT_SelectionRequest_MULTIPLE
(
event
);
goto
END
;
}
/* Lookup the requested target property in the cache */
if
(
!
LookupCacheItem
(
event
->
selection
,
event
->
target
,
&
pCacheEntry
)
)
{
TRACE
(
"Item not available in cache!
\n
"
);
goto
END
;
}
/* Update the X property */
TRACE
(
"
\t
Updating property %s..."
,
XGetAtomName
(
g_display
,
rprop
));
/* If we have a request for a pixmap, return a duplicate */
if
(
event
->
target
==
XA_PIXMAP
||
event
->
target
==
XA_BITMAP
)
{
Pixmap
*
pPixmap
=
(
Pixmap
*
)
pCacheEntry
->
pData
;
pixmap
=
DuplicatePixmap
(
*
pPixmap
);
pData
=
&
pixmap
;
}
else
pData
=
pCacheEntry
->
pData
;
XChangeProperty
(
g_display
,
request
,
rprop
,
pCacheEntry
->
type
,
pCacheEntry
->
nFormat
,
PropModeReplace
,
(
unsigned
char
*
)
pData
,
pCacheEntry
->
nElements
);
END:
if
(
rprop
==
None
)
TRACE
(
"
\t
Request ignored
\n
"
);
/* reply to sender
* SelectionNotify should be sent only at the end of a MULTIPLE request
*/
if
(
!
bIsMultiple
)
{
result
.
type
=
SelectionNotify
;
result
.
display
=
g_display
;
result
.
requestor
=
request
;
result
.
selection
=
event
->
selection
;
result
.
property
=
rprop
;
result
.
target
=
event
->
target
;
result
.
time
=
event
->
time
;
TRACE
(
"Sending SelectionNotify event...
\n
"
);
XSendEvent
(
g_display
,
event
->
requestor
,
False
,
NoEventMask
,(
XEvent
*
)
&
result
);
}
}
/***********************************************************************
* EVENT_SelectionClear
* We receive this event when another client grabs the X selection.
* If we lost both PRIMARY and CLIPBOARD we must terminate.
*/
void
EVENT_SelectionClear
(
XSelectionClearEvent
*
event
)
{
Atom
xaClipboard
=
XInternAtom
(
g_display
,
_CLIPBOARD
,
False
);
TRACE
(
"()
\n
"
);
if
(
event
->
selection
==
XA_PRIMARY
)
{
g_selectionAcquired
&=
~
S_PRIMARY
;
/* Clear the PRIMARY flag */
TRACE
(
"Lost PRIMARY selection...
\n
"
);
}
else
if
(
event
->
selection
==
xaClipboard
)
{
g_selectionAcquired
&=
~
S_CLIPBOARD
;
/* Clear the CLIPBOARD flag */
TRACE
(
"Lost CLIPBOARD selection...
\n
"
);
}
/* Once we lose all our selections we have nothing more to do */
if
(
g_selectionAcquired
==
S_NOSELECTION
)
TerminateServer
(
1
);
}
/***********************************************************************
* EVENT_PropertyNotify
* We use this to release resources like Pixmaps when a selection
* client no longer needs them.
*/
void
EVENT_PropertyNotify
(
XPropertyEvent
*
event
)
{
TRACE
(
"()
\n
"
);
/* Check if we have any resources to free */
switch
(
event
->
state
)
{
case
PropertyDelete
:
{
TRACE
(
"
\t
PropertyDelete for atom %s on window %ld
\n
"
,
XGetAtomName
(
event
->
display
,
event
->
atom
),
(
long
)
event
->
window
);
/* FreeResources( event->atom ); */
break
;
}
case
PropertyNewValue
:
{
TRACE
(
"
\t
PropertyNewValue for atom %s on window %ld
\n\n
"
,
XGetAtomName
(
event
->
display
,
event
->
atom
),
(
long
)
event
->
window
);
break
;
}
default:
break
;
}
}
/***********************************************************************
* DuplicatePixmap
*/
Pixmap
DuplicatePixmap
(
Pixmap
pixmap
)
{
Pixmap
newPixmap
;
XImage
*
xi
;
Window
root
;
int
x
,
y
;
/* Unused */
unsigned
border_width
;
/* Unused */
unsigned
int
depth
,
width
,
height
;
TRACE
(
"
\t
() Pixmap=%ul
\n
"
,
pixmap
);
/* Get the Pixmap dimensions and bit depth */
if
(
0
==
XGetGeometry
(
g_display
,
pixmap
,
&
root
,
&
x
,
&
y
,
&
width
,
&
height
,
&
border_width
,
&
depth
)
)
return
0
;
TRACE
(
"
\t
Pixmap properties: width=%d, height=%d, depth=%d
\n
"
,
width
,
height
,
depth
);
newPixmap
=
XCreatePixmap
(
g_display
,
g_win
,
width
,
height
,
depth
);
xi
=
XGetImage
(
g_display
,
pixmap
,
0
,
0
,
width
,
height
,
AllPlanes
,
XYPixmap
);
XPutImage
(
g_display
,
newPixmap
,
g_gc
,
xi
,
0
,
0
,
0
,
0
,
width
,
height
);
XDestroyImage
(
xi
);
TRACE
(
"
\t
() New Pixmap=%ul
\n
"
,
newPixmap
);
return
newPixmap
;
}
/***********************************************************************
* getGC
* Get a GC to use for drawing
*/
void
getGC
(
Window
win
,
GC
*
gc
)
{
unsigned
long
valuemask
=
0
;
/* ignore XGCvalues and use defaults */
XGCValues
values
;
unsigned
int
line_width
=
6
;
int
line_style
=
LineOnOffDash
;
int
cap_style
=
CapRound
;
int
join_style
=
JoinRound
;
int
dash_offset
=
0
;
static
char
dash_list
[]
=
{
12
,
24
};
int
list_length
=
2
;
/* Create default Graphics Context */
*
gc
=
XCreateGC
(
g_display
,
win
,
valuemask
,
&
values
);
/* specify black foreground since default window background is
* white and default foreground is undefined. */
XSetForeground
(
g_display
,
*
gc
,
BlackPixel
(
g_display
,
screen_num
));
/* set line attributes */
XSetLineAttributes
(
g_display
,
*
gc
,
line_width
,
line_style
,
cap_style
,
join_style
);
/* set dashes */
XSetDashes
(
g_display
,
*
gc
,
dash_offset
,
dash_list
,
list_length
);
}
/***********************************************************************
* TextOut
*/
void
TextOut
(
Window
win
,
GC
gc
,
char
*
pStr
)
{
int
y_offset
,
x_offset
;
y_offset
=
10
;
x_offset
=
2
;
/* output text, centered on each line */
XDrawString
(
g_display
,
win
,
gc
,
x_offset
,
y_offset
,
pStr
,
strlen
(
pStr
));
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment