mirror of
https://github.com/gryf/wmaker.git
synced 2026-01-07 22:34:18 +01:00
Initial revision
This commit is contained in:
663
WINGs/wview.c
Normal file
663
WINGs/wview.c
Normal file
@@ -0,0 +1,663 @@
|
||||
|
||||
|
||||
#include "WINGsP.h"
|
||||
|
||||
#include <X11/Xresource.h>
|
||||
|
||||
|
||||
|
||||
/* the notifications about views */
|
||||
|
||||
char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
|
||||
char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
|
||||
char *WMViewRealizedNotification = "WMViewRealizedNotification";
|
||||
|
||||
|
||||
#define EVENT_MASK \
|
||||
KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
|
||||
EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
|
||||
VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
|
||||
SubstructureNotifyMask|SubstructureRedirectMask
|
||||
|
||||
|
||||
static XSetWindowAttributes defAtts= {
|
||||
None, /* background_pixmap */
|
||||
0, /* background_pixel */
|
||||
CopyFromParent, /* border_pixmap */
|
||||
0, /* border_pixel */
|
||||
ForgetGravity, /* bit_gravity */
|
||||
ForgetGravity, /* win_gravity */
|
||||
NotUseful, /* backing_store */
|
||||
(unsigned) ~0, /* backing_planes */
|
||||
0, /* backing_pixel */
|
||||
False, /* save_under */
|
||||
EVENT_MASK, /* event_mask */
|
||||
0, /* do_not_propagate_mask */
|
||||
False, /* override_redirect */
|
||||
None, /* colormap */
|
||||
None /* cursor */
|
||||
};
|
||||
|
||||
|
||||
|
||||
static XContext ViewContext=0; /* context for views */
|
||||
|
||||
|
||||
|
||||
|
||||
W_View*
|
||||
W_GetViewForXWindow(Display *display, Window window)
|
||||
{
|
||||
W_View *view;
|
||||
|
||||
if (XFindContext(display, window, ViewContext, (XPointer*)&view)==0) {
|
||||
return view;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
unparentView(W_View *view)
|
||||
{
|
||||
/* remove from parent's children list */
|
||||
if (view->parent!=NULL) {
|
||||
W_View *ptr;
|
||||
|
||||
ptr = view->parent->childrenList;
|
||||
if (ptr == view) {
|
||||
view->parent->childrenList = view->nextSister;
|
||||
} else {
|
||||
while (ptr!=NULL) {
|
||||
if (ptr->nextSister == view) {
|
||||
ptr->nextSister = view->nextSister;
|
||||
break;
|
||||
}
|
||||
ptr = ptr->nextSister;
|
||||
}
|
||||
}
|
||||
}
|
||||
view->parent = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
adoptChildView(W_View *view, W_View *child)
|
||||
{
|
||||
child->nextSister = NULL;
|
||||
|
||||
/* add to end of children list of parent */
|
||||
if (view->childrenList == NULL) {
|
||||
view->childrenList = child;
|
||||
} else {
|
||||
W_View *ptr;
|
||||
|
||||
ptr = view->childrenList;
|
||||
while (ptr->nextSister!=NULL)
|
||||
ptr = ptr->nextSister;
|
||||
ptr->nextSister = child;
|
||||
}
|
||||
child->parent = view;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handleEvents(XEvent *event, void *data)
|
||||
{
|
||||
W_View *view = (W_View*)data;
|
||||
|
||||
if (event->type == ConfigureNotify) {
|
||||
|
||||
if (event->xconfigure.width != view->size.width
|
||||
|| event->xconfigure.height != view->size.height) {
|
||||
|
||||
if (view->flags.notifySizeChanged) {
|
||||
view->size.width = event->xconfigure.width;
|
||||
view->size.height = event->xconfigure.height;
|
||||
WMPostNotificationName(WMViewSizeDidChangeNotification,
|
||||
view, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static W_View*
|
||||
createView(W_Screen *screen, W_View *parent)
|
||||
{
|
||||
W_View *view;
|
||||
|
||||
if (ViewContext==0)
|
||||
ViewContext = XUniqueContext();
|
||||
|
||||
view = wmalloc(sizeof(W_View));
|
||||
memset(view, 0, sizeof(W_View));
|
||||
|
||||
view->refCount = 1;
|
||||
|
||||
view->screen = screen;
|
||||
|
||||
if (parent!=NULL) {
|
||||
/* attributes are not valid for root window */
|
||||
view->attribFlags = CWEventMask|CWBitGravity;
|
||||
view->attribs = defAtts;
|
||||
|
||||
view->attribFlags |= CWBackPixel|CWColormap;
|
||||
view->attribs.background_pixel = W_PIXEL(screen->gray);
|
||||
view->attribs.colormap = screen->colormap;
|
||||
|
||||
adoptChildView(parent, view);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
|
||||
W_View*
|
||||
W_CreateView(W_View *parent)
|
||||
{
|
||||
return createView(parent->screen, parent);
|
||||
}
|
||||
|
||||
|
||||
W_View*
|
||||
W_CreateRootView(W_Screen *screen)
|
||||
{
|
||||
W_View *view;
|
||||
|
||||
view = createView(screen, NULL);
|
||||
|
||||
view->window = screen->rootWin;
|
||||
|
||||
view->flags.realized = 1;
|
||||
view->flags.mapped = 1;
|
||||
view->flags.root = 1;
|
||||
|
||||
view->size.width =
|
||||
WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
|
||||
view->size.height =
|
||||
HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
W_View*
|
||||
W_CreateTopView(W_Screen *screen)
|
||||
{
|
||||
W_View *view;
|
||||
|
||||
view = createView(screen, screen->rootView);
|
||||
if (!view)
|
||||
return NULL;
|
||||
|
||||
view->flags.topLevel = 1;
|
||||
view->attribs.event_mask |= StructureNotifyMask;
|
||||
|
||||
/* catch changes in the toplevel window (resize from user etc.) */
|
||||
WMCreateEventHandler(view, StructureNotifyMask, handleEvents, view);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_RealizeView(W_View *view)
|
||||
{
|
||||
Window parentWID;
|
||||
Display *dpy = view->screen->display;
|
||||
W_View *ptr;
|
||||
|
||||
assert(view->size.width > 0);
|
||||
assert(view->size.height > 0);
|
||||
|
||||
|
||||
if (view->parent && !view->parent->flags.realized) {
|
||||
wwarning("trying to realize widget of unrealized parent");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!view->flags.realized) {
|
||||
parentWID = view->parent->window;
|
||||
view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
|
||||
view->size.width, view->size.height, 0,
|
||||
view->screen->depth, InputOutput,
|
||||
view->screen->visual, view->attribFlags,
|
||||
&view->attribs);
|
||||
|
||||
XSaveContext(dpy, view->window, ViewContext, (XPointer)view);
|
||||
|
||||
view->flags.realized = 1;
|
||||
|
||||
if (view->flags.mapWhenRealized) {
|
||||
W_MapView(view);
|
||||
view->flags.mapWhenRealized = 0;
|
||||
}
|
||||
|
||||
WMPostNotificationName(WMViewRealizedNotification, view, NULL);
|
||||
}
|
||||
|
||||
/* realize children */
|
||||
ptr = view->childrenList;
|
||||
while (ptr!=NULL) {
|
||||
W_RealizeView(ptr);
|
||||
|
||||
ptr = ptr->nextSister;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Bool
|
||||
W_CheckInternalMessage(W_Screen *scr, XClientMessageEvent *cev, int event)
|
||||
{
|
||||
if (cev->message_type == scr->internalMessage
|
||||
&& cev->format == 32 && cev->data.l[1] == event)
|
||||
return True;
|
||||
else
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_ReparentView(W_View *view, W_View *newParent)
|
||||
{
|
||||
int wasMapped;
|
||||
Display *dpy = view->screen->display;
|
||||
|
||||
assert(!view->flags.topLevel);
|
||||
|
||||
wasMapped = view->flags.mapped;
|
||||
if (wasMapped)
|
||||
W_UnmapView(view);
|
||||
|
||||
unparentView(view);
|
||||
adoptChildView(newParent, view);
|
||||
|
||||
if (view->flags.realized) {
|
||||
if (newParent->flags.realized) {
|
||||
XReparentWindow(dpy, view->window, newParent->window, 0, 0);
|
||||
} else {
|
||||
wwarning("trying to reparent realized view to unrealized parent");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
view->pos.x = 0;
|
||||
view->pos.y = 0;
|
||||
|
||||
if (wasMapped)
|
||||
W_MapView(view);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_MapView(W_View *view)
|
||||
{
|
||||
if (!view->flags.mapped) {
|
||||
if (view->flags.realized) {
|
||||
XMapRaised(view->screen->display, view->window);
|
||||
XFlush(view->screen->display);
|
||||
view->flags.mapped = 1;
|
||||
} else {
|
||||
view->flags.mapWhenRealized = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* W_MapSubviews-
|
||||
* maps all children of the current view that where already realized.
|
||||
*/
|
||||
void
|
||||
W_MapSubviews(W_View *view)
|
||||
{
|
||||
XMapSubwindows(view->screen->display, view->window);
|
||||
XFlush(view->screen->display);
|
||||
|
||||
view = view->childrenList;
|
||||
while (view) {
|
||||
view->flags.mapped = 1;
|
||||
view->flags.mapWhenRealized = 0;
|
||||
view = view->nextSister;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_UnmapSubviews(W_View *view)
|
||||
{
|
||||
XUnmapSubwindows(view->screen->display, view->window);
|
||||
XFlush(view->screen->display);
|
||||
|
||||
view = view->childrenList;
|
||||
while (view) {
|
||||
view->flags.mapped = 0;
|
||||
view->flags.mapWhenRealized = 0;
|
||||
view = view->nextSister;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_UnmapView(W_View *view)
|
||||
{
|
||||
view->flags.mapWhenRealized = 0;
|
||||
if (!view->flags.mapped)
|
||||
return;
|
||||
|
||||
XUnmapWindow(view->screen->display, view->window);
|
||||
XFlush(view->screen->display);
|
||||
|
||||
view->flags.mapped = 0;
|
||||
}
|
||||
|
||||
|
||||
W_View*
|
||||
W_TopLevelOfView(W_View *view)
|
||||
{
|
||||
W_View *toplevel;
|
||||
|
||||
for (toplevel=view; !toplevel->flags.topLevel; toplevel=toplevel->parent);
|
||||
|
||||
return toplevel;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
destroyView(W_View *view)
|
||||
{
|
||||
W_View *ptr;
|
||||
|
||||
if (view->flags.alreadyDead)
|
||||
return;
|
||||
view->flags.alreadyDead = 1;
|
||||
|
||||
/* Do not leave focus in a inexisting control */
|
||||
if (W_FocusedViewOfToplevel(W_TopLevelOfView(view))==view)
|
||||
W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
|
||||
|
||||
if (view->flags.topLevel) {
|
||||
W_FocusInfo *info = view->screen->focusInfo;
|
||||
/* remove focus information associated to this toplevel */
|
||||
|
||||
if (info) {
|
||||
if (info->toplevel==view) {
|
||||
view->screen->focusInfo = info->next;
|
||||
free(info);
|
||||
} else {
|
||||
while (info->next) {
|
||||
if (info->next->toplevel == view)
|
||||
break;
|
||||
info = info->next;
|
||||
}
|
||||
if (info->next) {
|
||||
W_FocusInfo *next = info->next->next;
|
||||
free(info->next);
|
||||
info->next = next;
|
||||
}
|
||||
/* else the toplevel did not have any focused subview */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* destroy children recursively */
|
||||
while (view->childrenList!=NULL) {
|
||||
ptr = view->childrenList;
|
||||
ptr->flags.parentDying = 1;
|
||||
|
||||
W_DestroyView(ptr);
|
||||
|
||||
if (ptr == view->childrenList) {
|
||||
view->childrenList = ptr->nextSister;
|
||||
ptr->parent = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
W_CallDestroyHandlers(view);
|
||||
|
||||
if (view->flags.realized) {
|
||||
XDeleteContext(view->screen->display, view->window, ViewContext);
|
||||
|
||||
/* if parent is being destroyed, it will die naturaly */
|
||||
if (!view->flags.parentDying || view->flags.topLevel)
|
||||
XDestroyWindow(view->screen->display, view->window);
|
||||
}
|
||||
|
||||
/* remove self from parent's children list */
|
||||
unparentView(view);
|
||||
|
||||
W_CleanUpEvents(view);
|
||||
#if 0
|
||||
if (view->dragSourceProcs)
|
||||
free(view->dragSourceProcs);
|
||||
|
||||
if (view->dragDestinationProcs)
|
||||
free(view->dragDestinationProcs);
|
||||
#endif
|
||||
free(view);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_DestroyView(W_View *view)
|
||||
{
|
||||
W_ReleaseView(view);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_MoveView(W_View *view, int x, int y)
|
||||
{
|
||||
assert(view->flags.root==0);
|
||||
|
||||
if (view->pos.x == x && view->pos.y == y)
|
||||
return;
|
||||
|
||||
if (view->flags.realized) {
|
||||
XMoveWindow(view->screen->display, view->window, x, y);
|
||||
}
|
||||
view->pos.x = x;
|
||||
view->pos.y = y;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_ResizeView(W_View *view, unsigned int width, unsigned int height)
|
||||
{
|
||||
int shrinked;
|
||||
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
|
||||
if (view->size.width == width && view->size.height == height)
|
||||
return;
|
||||
|
||||
shrinked = width < view->size.width || height < view->size.height;
|
||||
|
||||
if (view->flags.realized) {
|
||||
XResizeWindow(view->screen->display, view->window, width, height);
|
||||
}
|
||||
view->size.width = width;
|
||||
view->size.height = height;
|
||||
|
||||
if (view->flags.notifySizeChanged)
|
||||
WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_RedisplayView(W_View *view)
|
||||
{
|
||||
XExposeEvent ev;
|
||||
|
||||
if (!view->flags.mapped)
|
||||
return;
|
||||
|
||||
ev.type = Expose;
|
||||
ev.display = view->screen->display;
|
||||
ev.window = view->window;
|
||||
ev.count = 0;
|
||||
|
||||
WMHandleEvent((XEvent*)&ev);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_SetViewBackgroundColor(W_View *view, WMColor *color)
|
||||
{
|
||||
view->attribFlags |= CWBackPixel;
|
||||
view->attribs.background_pixel = color->color.pixel;
|
||||
if (view->flags.realized) {
|
||||
XSetWindowBackground(view->screen->display, view->window,
|
||||
color->color.pixel);
|
||||
XClearWindow(view->screen->display, view->window);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
W_View*
|
||||
W_FocusedViewOfToplevel(W_View *view)
|
||||
{
|
||||
WMScreen *scr = view->screen;
|
||||
W_FocusInfo *info;
|
||||
|
||||
for (info = scr->focusInfo; info!=NULL; info = info->next)
|
||||
if (view == info->toplevel)
|
||||
break;
|
||||
|
||||
if (!info)
|
||||
return NULL;
|
||||
|
||||
return info->focused;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_SetFocusOfTopLevel(W_View *toplevel, W_View *view)
|
||||
{
|
||||
WMScreen *scr = toplevel->screen;
|
||||
XEvent event;
|
||||
W_FocusInfo *info;
|
||||
|
||||
for (info = scr->focusInfo; info!=NULL; info = info->next)
|
||||
if (toplevel == info->toplevel)
|
||||
break;
|
||||
|
||||
if (!info) {
|
||||
info = wmalloc(sizeof(W_FocusInfo));
|
||||
info->toplevel = toplevel;
|
||||
info->focused = view;
|
||||
info->next = scr->focusInfo;
|
||||
scr->focusInfo = info;
|
||||
} else {
|
||||
event.xfocus.mode = NotifyNormal;
|
||||
event.xfocus.detail = NotifyDetailNone;
|
||||
if (info->focused) {
|
||||
/* simulate FocusOut event */
|
||||
event.xfocus.type = FocusOut;
|
||||
W_DispatchMessage(info->focused, &event);
|
||||
}
|
||||
info->focused = view;
|
||||
}
|
||||
if (view) {
|
||||
/* simulate FocusIn event */
|
||||
event.xfocus.type = FocusIn;
|
||||
W_DispatchMessage(view, &event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_BroadcastMessage(W_View *targetParent, XEvent *event)
|
||||
{
|
||||
W_View *target;
|
||||
|
||||
target = targetParent->childrenList;
|
||||
while (target!=NULL) {
|
||||
W_DispatchMessage(target, event);
|
||||
|
||||
target = target->nextSister;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
W_DispatchMessage(W_View *target, XEvent *event)
|
||||
{
|
||||
if (target->window==None)
|
||||
return;
|
||||
event->xclient.window = target->window;
|
||||
event->xclient.display = target->screen->display;
|
||||
|
||||
WMHandleEvent(event);
|
||||
/*
|
||||
XSendEvent(target->screen->display, target->window, False,
|
||||
SubstructureNotifyMask, event);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
||||
WMView*
|
||||
W_RetainView(WMView *view)
|
||||
{
|
||||
view->refCount++;
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
W_ReleaseView(WMView *view)
|
||||
{
|
||||
view->refCount--;
|
||||
if (view->refCount < 1) {
|
||||
destroyView(view);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WMWidget*
|
||||
WMWidgetOfView(WMView *view)
|
||||
{
|
||||
return view->self;
|
||||
}
|
||||
|
||||
|
||||
WMSize
|
||||
WMGetViewSize(WMView *view)
|
||||
{
|
||||
return view->size;
|
||||
}
|
||||
|
||||
WMPoint
|
||||
WMGetViewPosition(WMView *view)
|
||||
{
|
||||
return view->pos;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
WMSetViewNotifySizeChanges(WMView *view, Bool flag)
|
||||
{
|
||||
view->flags.notifySizeChanged = flag;
|
||||
}
|
||||
|
||||
Window
|
||||
WMViewXID(WMView *view)
|
||||
{
|
||||
return view->window;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user