mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 12:28:22 +01:00
added responder chain alike stuff for relaying kbd events from widget to widget
This commit is contained in:
@@ -433,6 +433,12 @@ int WMGetTableViewClickedRow(WMTableView *table)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WMArray *WMGetTableViewSelectedRows(WMTableView *table)
|
||||||
|
{
|
||||||
|
return table->selectedRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
WMView *WMGetTableViewDocumentView(WMTableView *table)
|
WMView *WMGetTableViewDocumentView(WMTableView *table)
|
||||||
{
|
{
|
||||||
return table->tableView;
|
return table->tableView;
|
||||||
|
|||||||
@@ -77,6 +77,8 @@ void *WMGetTableViewClickedColumn(WMTableView *table);
|
|||||||
|
|
||||||
int WMGetTableViewClickedRow(WMTableView *table);
|
int WMGetTableViewClickedRow(WMTableView *table);
|
||||||
|
|
||||||
|
WMArray *WMGetTableViewSelectedRows(WMTableView *table);
|
||||||
|
|
||||||
WMView *WMGetTableViewDocumentView(WMTableView *table);
|
WMView *WMGetTableViewDocumentView(WMTableView *table);
|
||||||
|
|
||||||
void WMEditTableViewRow(WMTableView *table, int row);
|
void WMEditTableViewRow(WMTableView *table, int row);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <WINGs/WUtil.h>
|
#include <WINGs/WUtil.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
#define WINGS_H_VERSION 20000521
|
#define WINGS_H_VERSION 20010117
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -849,6 +849,10 @@ WMPoint WMGetViewScreenPosition(WMView *view);
|
|||||||
|
|
||||||
WMWidget *WMWidgetOfView(WMView *view);
|
WMWidget *WMWidgetOfView(WMView *view);
|
||||||
|
|
||||||
|
void WMSetViewNextResponder(WMView *view, WMView *responder);
|
||||||
|
|
||||||
|
void WMRelayToNextResponder(WMView *view, XEvent *event);
|
||||||
|
|
||||||
/* notifications */
|
/* notifications */
|
||||||
extern char *WMViewSizeDidChangeNotification;
|
extern char *WMViewSizeDidChangeNotification;
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include <WINGs/WINGs.h>
|
#include <WINGs/WINGs.h>
|
||||||
|
|
||||||
#if WINGS_H_VERSION < 20000521
|
#if WINGS_H_VERSION < 20010117
|
||||||
#error There_is_an_old_WINGs.h_file_somewhere_in_your_system._Please_remove_it.
|
#error There_is_an_old_WINGs.h_file_somewhere_in_your_system._Please_remove_it.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -322,6 +322,8 @@ typedef struct W_View {
|
|||||||
struct W_View *nextFocusChain; /* next/prev in focus chain */
|
struct W_View *nextFocusChain; /* next/prev in focus chain */
|
||||||
struct W_View *prevFocusChain;
|
struct W_View *prevFocusChain;
|
||||||
|
|
||||||
|
struct W_View *nextResponder; /* next to receive keyboard events */
|
||||||
|
|
||||||
struct W_View *parent; /* parent WMView */
|
struct W_View *parent; /* parent WMView */
|
||||||
|
|
||||||
struct W_View *childrenList; /* first in list of child windows */
|
struct W_View *childrenList; /* first in list of child windows */
|
||||||
|
|||||||
@@ -523,6 +523,36 @@ W_CallDestroyHandlers(W_View *view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WMSetViewNextResponder(WMView *view, WMView *responder)
|
||||||
|
{
|
||||||
|
/* set the widget to receive keyboard events that aren't handled
|
||||||
|
* by this widget */
|
||||||
|
|
||||||
|
view->nextResponder = responder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WMRelayToNextResponder(WMView *view, XEvent *event)
|
||||||
|
{
|
||||||
|
unsigned long mask = eventMasks[event->xany.type];
|
||||||
|
|
||||||
|
if (view->nextResponder) {
|
||||||
|
WMView *next = view->nextResponder;
|
||||||
|
W_EventHandler *hPtr;
|
||||||
|
WMBagIterator iter;
|
||||||
|
|
||||||
|
WM_ITERATE_BAG(next->eventHandlers, hPtr, iter) {
|
||||||
|
if ((hPtr->eventMask & mask)) {
|
||||||
|
(*hPtr->proc)(event, hPtr->clientData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
WMHandleEvent(XEvent *event)
|
WMHandleEvent(XEvent *event)
|
||||||
{
|
{
|
||||||
@@ -627,7 +657,7 @@ WMHandleEvent(XEvent *event)
|
|||||||
(*hPtr->proc)(event, hPtr->clientData);
|
(*hPtr->proc)(event, hPtr->clientData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
/* pass the event to the top level window of the widget */
|
/* pass the event to the top level window of the widget */
|
||||||
/* TODO: change this to a responder chain */
|
/* TODO: change this to a responder chain */
|
||||||
if (view->parent != NULL) {
|
if (view->parent != NULL) {
|
||||||
@@ -641,7 +671,7 @@ WMHandleEvent(XEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
/* save button click info to track double-clicks */
|
/* save button click info to track double-clicks */
|
||||||
if (view->screen->ignoreNextDoubleClick) {
|
if (view->screen->ignoreNextDoubleClick) {
|
||||||
view->screen->ignoreNextDoubleClick = 0;
|
view->screen->ignoreNextDoubleClick = 0;
|
||||||
|
|||||||
@@ -571,10 +571,6 @@ static void
|
|||||||
popDownMenu(PopUpButton *bPtr)
|
popDownMenu(PopUpButton *bPtr)
|
||||||
{
|
{
|
||||||
W_UnmapView(bPtr->menuView);
|
W_UnmapView(bPtr->menuView);
|
||||||
|
|
||||||
/* free the background pixmap used to draw the menu contents */
|
|
||||||
XSetWindowBackgroundPixmap(bPtr->view->screen->display,
|
|
||||||
bPtr->menuView->window, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2312,6 +2312,8 @@ R_imaGFX: if(tb->next) {
|
|||||||
}
|
}
|
||||||
else if (control_pressed && buffer[0] == '')
|
else if (control_pressed && buffer[0] == '')
|
||||||
XBell(tPtr->view->screen->display, 0);
|
XBell(tPtr->view->screen->display, 0);
|
||||||
|
else
|
||||||
|
WMRelayToNextResponder(tPtr->view, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!control_pressed && tPtr->flags.ownsSelection)
|
if (!control_pressed && tPtr->flags.ownsSelection)
|
||||||
|
|||||||
@@ -998,11 +998,21 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
int count, refresh = 0;
|
int count, refresh = 0;
|
||||||
int control_pressed = 0;
|
int control_pressed = 0;
|
||||||
int cancelSelection = 1;
|
int cancelSelection = 1;
|
||||||
|
Bool shifted, controled, modified;
|
||||||
|
Bool relay = True;
|
||||||
|
|
||||||
/*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count);*/
|
/*printf("(%d,%d) -> ", tPtr->selection.position, tPtr->selection.count);*/
|
||||||
if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK)
|
if (((XKeyEvent *) event)->state & WM_EMACSKEYMASK)
|
||||||
control_pressed = 1;
|
control_pressed = 1;
|
||||||
|
|
||||||
|
shifted = event->xkey.state & ShiftMask;
|
||||||
|
controled = event->xkey.state & ControlMask;
|
||||||
|
if ((event->xkey.state & ~(ShiftMask|ControlMask)) != 0) {
|
||||||
|
modified = True;
|
||||||
|
} else {
|
||||||
|
modified = False;
|
||||||
|
}
|
||||||
|
|
||||||
count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
|
count = XLookupString(&event->xkey, buffer, 63, &ksym, NULL);
|
||||||
buffer[count] = '\0';
|
buffer[count] = '\0';
|
||||||
|
|
||||||
@@ -1011,7 +1021,8 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
#ifdef XK_ISO_Left_Tab
|
#ifdef XK_ISO_Left_Tab
|
||||||
case XK_ISO_Left_Tab:
|
case XK_ISO_Left_Tab:
|
||||||
#endif
|
#endif
|
||||||
if (event->xkey.state & ShiftMask) {
|
if (!controled && !modified) {
|
||||||
|
if (shifted) {
|
||||||
if (tPtr->view->prevFocusChain) {
|
if (tPtr->view->prevFocusChain) {
|
||||||
W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
|
W_SetFocusOfTopLevel(W_TopLevelOfView(tPtr->view),
|
||||||
tPtr->view->prevFocusChain);
|
tPtr->view->prevFocusChain);
|
||||||
@@ -1027,16 +1038,27 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
data = (void*)WMTabTextMovement;
|
data = (void*)WMTabTextMovement;
|
||||||
}
|
}
|
||||||
textEvent = WMTextDidEndEditingNotification;
|
textEvent = WMTextDidEndEditingNotification;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XK_Escape:
|
case XK_Escape:
|
||||||
|
if (!shifted && !controled && !modified) {
|
||||||
data = (void*)WMEscapeTextMovement;
|
data = (void*)WMEscapeTextMovement;
|
||||||
textEvent = WMTextDidEndEditingNotification;
|
textEvent = WMTextDidEndEditingNotification;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XK_Return:
|
case XK_Return:
|
||||||
|
if (!shifted && !controled && !modified) {
|
||||||
data = (void*)WMReturnTextMovement;
|
data = (void*)WMReturnTextMovement;
|
||||||
textEvent = WMTextDidEndEditingNotification;
|
textEvent = WMTextDidEndEditingNotification;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_LEFT:
|
case WM_EMACSKEY_LEFT:
|
||||||
@@ -1047,6 +1069,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
case XK_KP_Left:
|
case XK_KP_Left:
|
||||||
#endif
|
#endif
|
||||||
case XK_Left:
|
case XK_Left:
|
||||||
|
if (!modified) {
|
||||||
if (tPtr->cursorPosition > 0) {
|
if (tPtr->cursorPosition > 0) {
|
||||||
paintCursor(tPtr);
|
paintCursor(tPtr);
|
||||||
if (event->xkey.state & ControlMask) {
|
if (event->xkey.state & ControlMask) {
|
||||||
@@ -1067,6 +1090,9 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->xkey.state & ShiftMask)
|
if (event->xkey.state & ShiftMask)
|
||||||
cancelSelection = 0;
|
cancelSelection = 0;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_RIGHT:
|
case WM_EMACSKEY_RIGHT:
|
||||||
@@ -1077,6 +1103,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
case XK_KP_Right:
|
case XK_KP_Right:
|
||||||
#endif
|
#endif
|
||||||
case XK_Right:
|
case XK_Right:
|
||||||
|
if (!modified) {
|
||||||
if (tPtr->cursorPosition < tPtr->textLen) {
|
if (tPtr->cursorPosition < tPtr->textLen) {
|
||||||
paintCursor(tPtr);
|
paintCursor(tPtr);
|
||||||
if (event->xkey.state & ControlMask) {
|
if (event->xkey.state & ControlMask) {
|
||||||
@@ -1101,6 +1128,9 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->xkey.state & ShiftMask)
|
if (event->xkey.state & ShiftMask)
|
||||||
cancelSelection = 0;
|
cancelSelection = 0;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_HOME:
|
case WM_EMACSKEY_HOME:
|
||||||
@@ -1111,6 +1141,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
case XK_KP_Home:
|
case XK_KP_Home:
|
||||||
#endif
|
#endif
|
||||||
case XK_Home:
|
case XK_Home:
|
||||||
|
if (!modified && !controled) {
|
||||||
if (tPtr->cursorPosition > 0) {
|
if (tPtr->cursorPosition > 0) {
|
||||||
paintCursor(tPtr);
|
paintCursor(tPtr);
|
||||||
tPtr->cursorPosition = 0;
|
tPtr->cursorPosition = 0;
|
||||||
@@ -1122,6 +1153,9 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->xkey.state & ShiftMask)
|
if (event->xkey.state & ShiftMask)
|
||||||
cancelSelection = 0;
|
cancelSelection = 0;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_END:
|
case WM_EMACSKEY_END:
|
||||||
@@ -1132,6 +1166,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
case XK_KP_End:
|
case XK_KP_End:
|
||||||
#endif
|
#endif
|
||||||
case XK_End:
|
case XK_End:
|
||||||
|
if (!modified && !controled) {
|
||||||
if (tPtr->cursorPosition < tPtr->textLen) {
|
if (tPtr->cursorPosition < tPtr->textLen) {
|
||||||
paintCursor(tPtr);
|
paintCursor(tPtr);
|
||||||
tPtr->cursorPosition = tPtr->textLen;
|
tPtr->cursorPosition = tPtr->textLen;
|
||||||
@@ -1148,6 +1183,9 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
}
|
}
|
||||||
if (event->xkey.state & ShiftMask)
|
if (event->xkey.state & ShiftMask)
|
||||||
cancelSelection = 0;
|
cancelSelection = 0;
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_BS:
|
case WM_EMACSKEY_BS:
|
||||||
@@ -1155,6 +1193,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
goto normal_key;
|
goto normal_key;
|
||||||
}
|
}
|
||||||
case XK_BackSpace:
|
case XK_BackSpace:
|
||||||
|
if (!modified && !shifted && !controled) {
|
||||||
if (tPtr->selection.count) {
|
if (tPtr->selection.count) {
|
||||||
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
||||||
data = (void*)WMDeleteTextEvent;
|
data = (void*)WMDeleteTextEvent;
|
||||||
@@ -1167,6 +1206,9 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
data = (void*)WMDeleteTextEvent;
|
data = (void*)WMDeleteTextEvent;
|
||||||
textEvent = WMTextDidChangeNotification;
|
textEvent = WMTextDidChangeNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_EMACSKEY_DEL:
|
case WM_EMACSKEY_DEL:
|
||||||
@@ -1177,6 +1219,7 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
case XK_KP_Delete:
|
case XK_KP_Delete:
|
||||||
#endif
|
#endif
|
||||||
case XK_Delete:
|
case XK_Delete:
|
||||||
|
if (!modified && !controled && !shifted) {
|
||||||
if (tPtr->selection.count) {
|
if (tPtr->selection.count) {
|
||||||
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
||||||
data = (void*)WMDeleteTextEvent;
|
data = (void*)WMDeleteTextEvent;
|
||||||
@@ -1189,23 +1232,34 @@ handleTextFieldKeyPress(TextField *tPtr, XEvent *event)
|
|||||||
data = (void*)WMDeleteTextEvent;
|
data = (void*)WMDeleteTextEvent;
|
||||||
textEvent = WMTextDidChangeNotification;
|
textEvent = WMTextDidChangeNotification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relay = False;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
normal_key:
|
normal_key:
|
||||||
default:
|
default:
|
||||||
|
if (!controled && !modified) {
|
||||||
if (count > 0 && isprint(buffer[0])) {
|
if (count > 0 && isprint(buffer[0])) {
|
||||||
if (tPtr->selection.count)
|
if (tPtr->selection.count)
|
||||||
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
WMDeleteTextFieldRange(tPtr, tPtr->selection);
|
||||||
WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
|
WMInsertTextFieldText(tPtr, buffer, tPtr->cursorPosition);
|
||||||
data = (void*)WMInsertTextEvent;
|
data = (void*)WMInsertTextEvent;
|
||||||
textEvent = WMTextDidChangeNotification;
|
textEvent = WMTextDidChangeNotification;
|
||||||
} else {
|
|
||||||
/* should we rather break and goto cancel selection below? -Dan */
|
relay = False;
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (relay) {
|
||||||
|
WMRelayToNextResponder(W_VIEW(tPtr), event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!cancelSelection) {
|
if (!cancelSelection) {
|
||||||
if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
|
if (tPtr->selection.count != tPtr->cursorPosition - tPtr->selection.position) {
|
||||||
|
|
||||||
@@ -1335,11 +1389,8 @@ handleTextFieldActionEvents(XEvent *event, void *data)
|
|||||||
}
|
}
|
||||||
if (tPtr->flags.enabled && tPtr->flags.focused) {
|
if (tPtr->flags.enabled && tPtr->flags.focused) {
|
||||||
handleTextFieldKeyPress(tPtr, event);
|
handleTextFieldKeyPress(tPtr, event);
|
||||||
XGrabPointer(dpy, W_VIEW(tPtr)->window, False,
|
XDefineCursor(dpy, W_VIEW(tPtr)->window,
|
||||||
PointerMotionMask|ButtonPressMask|ButtonReleaseMask,
|
W_VIEW(tPtr)->screen->invisibleCursor);
|
||||||
GrabModeAsync, GrabModeAsync, None,
|
|
||||||
W_VIEW(tPtr)->screen->invisibleCursor,
|
|
||||||
CurrentTime);
|
|
||||||
tPtr->flags.pointerGrabbed = 1;
|
tPtr->flags.pointerGrabbed = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1348,7 +1399,8 @@ handleTextFieldActionEvents(XEvent *event, void *data)
|
|||||||
|
|
||||||
if (tPtr->flags.pointerGrabbed) {
|
if (tPtr->flags.pointerGrabbed) {
|
||||||
tPtr->flags.pointerGrabbed = 0;
|
tPtr->flags.pointerGrabbed = 0;
|
||||||
XUngrabPointer(dpy, CurrentTime);
|
XDefineCursor(dpy, W_VIEW(tPtr)->window,
|
||||||
|
W_VIEW(tPtr)->screen->textCursor);
|
||||||
}
|
}
|
||||||
if (tPtr->flags.waitingSelection) {
|
if (tPtr->flags.waitingSelection) {
|
||||||
return;
|
return;
|
||||||
@@ -1393,7 +1445,8 @@ handleTextFieldActionEvents(XEvent *event, void *data)
|
|||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
if (tPtr->flags.pointerGrabbed) {
|
if (tPtr->flags.pointerGrabbed) {
|
||||||
tPtr->flags.pointerGrabbed = 0;
|
tPtr->flags.pointerGrabbed = 0;
|
||||||
XUngrabPointer(dpy, CurrentTime);
|
XDefineCursor(dpy, W_VIEW(tPtr)->window,
|
||||||
|
W_VIEW(tPtr)->screen->textCursor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1466,7 +1519,8 @@ handleTextFieldActionEvents(XEvent *event, void *data)
|
|||||||
case ButtonRelease:
|
case ButtonRelease:
|
||||||
if (tPtr->flags.pointerGrabbed) {
|
if (tPtr->flags.pointerGrabbed) {
|
||||||
tPtr->flags.pointerGrabbed = 0;
|
tPtr->flags.pointerGrabbed = 0;
|
||||||
XUngrabPointer(dpy, CurrentTime);
|
XDefineCursor(dpy, W_VIEW(tPtr)->window,
|
||||||
|
W_VIEW(tPtr)->screen->textCursor);
|
||||||
}
|
}
|
||||||
if (tPtr->flags.waitingSelection) {
|
if (tPtr->flags.waitingSelection) {
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -673,7 +673,6 @@ W_RetainView(WMView *view)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
W_ReleaseView(WMView *view)
|
W_ReleaseView(WMView *view)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user