Include screen.h in dialog.h for definition of WScreen
[wmaker-crm.git] / WINGs / wview.c
blob59dff304cef3b5adde69a8048db29de71d107101
2 #include "WINGsP.h"
4 #include <X11/Xresource.h>
6 /* the notifications about views */
8 const char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
9 const char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
10 const char *WMViewRealizedNotification = "WMViewRealizedNotification";
12 #define EVENT_MASK \
13 KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
14 EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
15 VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
16 SubstructureNotifyMask|SubstructureRedirectMask
18 static const XSetWindowAttributes defAtts = {
19 None, /* background_pixmap */
20 0, /* background_pixel */
21 CopyFromParent, /* border_pixmap */
22 0, /* border_pixel */
23 ForgetGravity, /* bit_gravity */
24 ForgetGravity, /* win_gravity */
25 NotUseful, /* backing_store */
26 (unsigned)~0, /* backing_planes */
27 0, /* backing_pixel */
28 False, /* save_under */
29 EVENT_MASK, /* event_mask */
30 0, /* do_not_propagate_mask */
31 False, /* override_redirect */
32 None, /* colormap */
33 None /* cursor */
36 static XContext ViewContext = 0; /* context for views */
38 W_View *W_GetViewForXWindow(Display * display, Window window)
40 W_View *view;
42 if (XFindContext(display, window, ViewContext, (XPointer *) & view) == 0) {
43 return view;
45 return NULL;
48 static void unparentView(W_View * view)
50 /* remove from parent's children list */
51 if (view->parent != NULL) {
52 W_View *ptr;
54 ptr = view->parent->childrenList;
55 if (ptr == view) {
56 view->parent->childrenList = view->nextSister;
57 } else {
58 while (ptr != NULL) {
59 if (ptr->nextSister == view) {
60 ptr->nextSister = view->nextSister;
61 break;
63 ptr = ptr->nextSister;
67 view->parent = NULL;
70 static void adoptChildView(W_View * view, W_View * child)
72 child->nextSister = NULL;
74 /* add to end of children list of parent */
75 if (view->childrenList == NULL) {
76 view->childrenList = child;
77 } else {
78 W_View *ptr;
80 ptr = view->childrenList;
81 while (ptr->nextSister != NULL)
82 ptr = ptr->nextSister;
83 ptr->nextSister = child;
85 child->parent = view;
88 static W_View *createView(W_Screen * screen, W_View * parent)
90 W_View *view;
92 if (ViewContext == 0)
93 ViewContext = XUniqueContext();
95 view = wmalloc(sizeof(W_View));
96 view->screen = screen;
98 if (parent != NULL) {
99 /* attributes are not valid for root window */
100 view->attribFlags = CWEventMask | CWBitGravity;
101 view->attribs = defAtts;
103 view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel | CWBackPixmap;
104 view->attribs.background_pixmap = None;
105 view->attribs.background_pixel = W_PIXEL(screen->gray);
106 view->attribs.border_pixel = W_PIXEL(screen->black);
107 view->attribs.colormap = screen->colormap;
109 view->backColor = WMRetainColor(screen->gray);
111 adoptChildView(parent, view);
114 view->xic = 0;
116 view->refCount = 1;
118 view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
120 return view;
123 W_View *W_CreateView(W_View * parent)
125 return createView(parent->screen, parent);
128 W_View *W_CreateRootView(W_Screen * screen)
130 W_View *view;
132 view = createView(screen, NULL);
134 view->window = screen->rootWin;
136 view->flags.realized = 1;
137 view->flags.mapped = 1;
138 view->flags.root = 1;
140 view->size.width = WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
141 view->size.height = HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
143 return view;
146 W_View *W_CreateTopView(W_Screen * screen)
148 W_View *view;
150 view = createView(screen, screen->rootView);
151 if (!view)
152 return NULL;
154 view->flags.topLevel = 1;
155 view->attribs.event_mask |= StructureNotifyMask;
157 return view;
160 W_View *W_CreateUnmanagedTopView(W_Screen * screen)
162 W_View *view;
164 view = createView(screen, screen->rootView);
165 if (!view)
166 return NULL;
168 view->flags.topLevel = 1;
169 view->attribs.event_mask |= StructureNotifyMask;
171 view->attribFlags |= CWOverrideRedirect;
172 view->attribs.override_redirect = True;
174 return view;
177 void W_RealizeView(W_View * view)
179 Window parentWID;
180 Display *dpy = view->screen->display;
181 W_View *ptr;
183 assert(view->size.width > 0);
184 assert(view->size.height > 0);
186 if (view->parent && !view->parent->flags.realized) {
187 wwarning("trying to realize widget of unrealized parent");
188 return;
191 if (!view->flags.realized) {
193 if (view->parent == NULL) {
194 wwarning("trying to realize widget without parent");
195 return;
198 parentWID = view->parent->window;
199 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
200 view->size.width, view->size.height, 0,
201 view->screen->depth, InputOutput,
202 view->screen->visual, view->attribFlags, &view->attribs);
204 XSaveContext(dpy, view->window, ViewContext, (XPointer) view);
206 view->flags.realized = 1;
208 if (view->flags.mapWhenRealized) {
209 W_MapView(view);
210 view->flags.mapWhenRealized = 0;
213 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
216 /* realize children */
217 ptr = view->childrenList;
218 while (ptr != NULL) {
219 W_RealizeView(ptr);
221 ptr = ptr->nextSister;
225 void W_ReparentView(W_View * view, W_View * newParent, int x, int y)
227 Display *dpy = view->screen->display;
229 assert(!view->flags.topLevel);
231 unparentView(view);
232 adoptChildView(newParent, view);
234 if (view->flags.realized) {
235 if (newParent->flags.realized) {
236 XReparentWindow(dpy, view->window, newParent->window, x, y);
237 } else {
238 wwarning("trying to reparent realized view to unrealized parent");
239 return;
243 view->pos.x = x;
244 view->pos.y = y;
247 void W_RaiseView(W_View * view)
249 if (W_VIEW_REALIZED(view))
250 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
253 void W_LowerView(W_View * view)
255 if (W_VIEW_REALIZED(view))
256 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
259 void W_MapView(W_View * view)
261 if (!view->flags.mapped) {
262 if (view->flags.realized) {
263 XMapRaised(view->screen->display, view->window);
264 XFlush(view->screen->display);
265 view->flags.mapped = 1;
266 } else {
267 view->flags.mapWhenRealized = 1;
273 * W_MapSubviews-
274 * maps all children of the current view that where already realized.
276 void W_MapSubviews(W_View * view)
278 XMapSubwindows(view->screen->display, view->window);
279 XFlush(view->screen->display);
281 view = view->childrenList;
282 while (view) {
283 view->flags.mapped = 1;
284 view->flags.mapWhenRealized = 0;
285 view = view->nextSister;
289 void W_UnmapSubviews(W_View * view)
291 XUnmapSubwindows(view->screen->display, view->window);
292 XFlush(view->screen->display);
294 view = view->childrenList;
295 while (view) {
296 view->flags.mapped = 0;
297 view->flags.mapWhenRealized = 0;
298 view = view->nextSister;
302 void W_UnmapView(W_View * view)
304 view->flags.mapWhenRealized = 0;
305 if (!view->flags.mapped)
306 return;
308 XUnmapWindow(view->screen->display, view->window);
309 XFlush(view->screen->display);
311 view->flags.mapped = 0;
314 W_View *W_TopLevelOfView(W_View * view)
316 W_View *toplevel;
318 for (toplevel = view; toplevel && !toplevel->flags.topLevel; toplevel = toplevel->parent) ;
320 return toplevel;
323 static void destroyView(W_View * view)
325 W_View *ptr;
327 if (view->flags.alreadyDead)
328 return;
329 view->flags.alreadyDead = 1;
331 /* delete the balloon text for the view, if there's any */
332 WMSetBalloonTextForView(NULL, view);
334 if (view->nextFocusChain)
335 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
336 if (view->prevFocusChain)
337 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
339 /* Do not leave focus in a inexisting control */
340 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view)) == view)
341 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
343 if (view->flags.topLevel) {
344 W_FocusInfo *info = view->screen->focusInfo;
345 /* remove focus information associated to this toplevel */
347 if (info) {
348 if (info->toplevel == view) {
349 view->screen->focusInfo = info->next;
350 wfree(info);
351 } else {
352 while (info->next) {
353 if (info->next->toplevel == view)
354 break;
355 info = info->next;
357 if (info->next) {
358 W_FocusInfo *next = info->next->next;
359 wfree(info->next);
360 info->next = next;
362 /* else the toplevel did not have any focused subview */
367 /* destroy children recursively */
368 while (view->childrenList != NULL) {
369 ptr = view->childrenList;
370 ptr->flags.parentDying = 1;
372 W_DestroyView(ptr);
374 if (ptr == view->childrenList) {
375 view->childrenList = ptr->nextSister;
376 ptr->parent = NULL;
380 W_CallDestroyHandlers(view);
382 if (view->flags.realized) {
383 XDeleteContext(view->screen->display, view->window, ViewContext);
385 /* if parent is being destroyed, it will die naturaly */
386 if (!view->flags.parentDying || view->flags.topLevel)
387 XDestroyWindow(view->screen->display, view->window);
390 /* remove self from parent's children list */
391 unparentView(view);
393 /* the array has a wfree() destructor that will be called automatically */
394 WMFreeArray(view->eventHandlers);
395 view->eventHandlers = NULL;
397 WMRemoveNotificationObserver(view);
399 W_FreeViewXdndPart(view);
401 if (view->backColor)
402 WMReleaseColor(view->backColor);
404 wfree(view);
407 void W_DestroyView(W_View * view)
409 view->refCount--;
411 if (view->refCount < 1) {
412 destroyView(view);
416 void W_MoveView(W_View * view, int x, int y)
418 assert(view->flags.root == 0);
420 if (view->delegate && view->delegate->willMove) {
421 (*view->delegate->willMove) (view->delegate, view, &x, &y);
424 if (view->pos.x == x && view->pos.y == y)
425 return;
427 if (view->flags.realized) {
428 XMoveWindow(view->screen->display, view->window, x, y);
430 view->pos.x = x;
431 view->pos.y = y;
433 if (view->delegate && view->delegate->didMove) {
434 (*view->delegate->didMove) (view->delegate, view);
438 void W_ResizeView(W_View * view, unsigned int width, unsigned int height)
440 /*int shrinked; */
442 if (view->delegate && view->delegate->willResize) {
443 (*view->delegate->willResize) (view->delegate, view, &width, &height);
446 assert(width > 0);
447 assert(height > 0);
449 if (view->size.width == width && view->size.height == height)
450 return;
452 /*shrinked = width < view->size.width || height < view->size.height; */
454 if (view->flags.realized) {
455 XResizeWindow(view->screen->display, view->window, width, height);
457 view->size.width = width;
458 view->size.height = height;
460 if (view->delegate && view->delegate->didResize) {
461 (*view->delegate->didResize) (view->delegate, view);
464 /* // TODO. replace in WINGs code, with the didResize delegate */
465 if (view->flags.notifySizeChanged)
466 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
469 void W_RedisplayView(W_View * view)
471 XEvent ev;
473 if (!view->flags.mapped)
474 return;
476 ev.xexpose.type = Expose;
477 ev.xexpose.display = view->screen->display;
478 ev.xexpose.window = view->window;
479 ev.xexpose.count = 0;
481 ev.xexpose.serial = 0;
483 WMHandleEvent(&ev);
486 void W_SetViewBackgroundColor(W_View * view, WMColor * color)
488 if (view->backColor)
489 WMReleaseColor(view->backColor);
490 view->backColor = WMRetainColor(color);
492 view->attribFlags |= CWBackPixel;
493 view->attribFlags &= ~CWBackPixmap;
494 view->attribs.background_pixel = W_PIXEL(color);
495 if (view->flags.realized) {
496 XSetWindowBackground(view->screen->display, view->window, W_PIXEL(color));
497 XClearWindow(view->screen->display, view->window);
501 void W_SetViewBackgroundPixmap(W_View *view, WMPixmap *pix)
503 if (view->backImage)
504 WMReleasePixmap(view->backImage);
505 view->backImage = WMRetainPixmap(pix);
507 view->attribFlags |= CWBackPixmap;
508 view->attribFlags &= ~CWBackPixel;
509 view->attribs.background_pixmap = pix->pixmap;
510 if (view->flags.realized) {
511 XSetWindowBackgroundPixmap(view->screen->display, view->window, pix->pixmap);
512 XClearWindow(view->screen->display, view->window);
516 void W_SetViewCursor(W_View * view, Cursor cursor)
518 view->cursor = cursor;
519 if (W_VIEW_REALIZED(view)) {
520 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
521 } else {
522 view->attribFlags |= CWCursor;
523 view->attribs.cursor = cursor;
527 W_View *W_FocusedViewOfToplevel(W_View * view)
529 WMScreen *scr = view->screen;
530 W_FocusInfo *info;
532 for (info = scr->focusInfo; info != NULL; info = info->next)
533 if (view == info->toplevel)
534 break;
536 if (!info)
537 return NULL;
539 return info->focused;
542 void W_SetFocusOfTopLevel(W_View * toplevel, W_View * view)
544 WMScreen *scr = toplevel->screen;
545 XEvent event;
546 W_FocusInfo *info;
548 for (info = scr->focusInfo; info != NULL; info = info->next)
549 if (toplevel == info->toplevel)
550 break;
552 if (!info) {
553 info = wmalloc(sizeof(W_FocusInfo));
554 info->toplevel = toplevel;
555 info->focused = view;
556 info->next = scr->focusInfo;
557 scr->focusInfo = info;
558 } else {
559 event.xfocus.mode = NotifyNormal;
560 event.xfocus.detail = NotifyDetailNone;
561 if (info->focused) {
562 /* simulate FocusOut event */
563 event.xfocus.type = FocusOut;
564 W_DispatchMessage(info->focused, &event);
566 info->focused = view;
568 if (view) {
569 /* simulate FocusIn event */
570 event.xfocus.type = FocusIn;
571 W_DispatchMessage(view, &event);
575 void W_BroadcastMessage(W_View * targetParent, XEvent * event)
577 W_View *target;
579 target = targetParent->childrenList;
580 while (target != NULL) {
581 W_DispatchMessage(target, event);
583 target = target->nextSister;
587 void W_DispatchMessage(W_View * target, XEvent * event)
589 if (target->window == None)
590 return;
591 event->xclient.window = target->window;
592 event->xclient.display = target->screen->display;
594 WMHandleEvent(event);
596 XSendEvent(target->screen->display, target->window, False,
597 SubstructureNotifyMask, event);
601 WMView *W_RetainView(WMView * view)
603 view->refCount++;
605 return view;
608 void W_ReleaseView(WMView * view)
610 view->refCount--;
612 if (view->refCount < 1) {
613 destroyView(view);
617 WMWidget *WMWidgetOfView(WMView * view)
619 return view->self;
622 WMSize WMGetViewSize(WMView * view)
624 return view->size;
627 WMPoint WMGetViewPosition(WMView * view)
629 return view->pos;
632 void WMSetViewNotifySizeChanges(WMView * view, Bool flag)
634 view->flags.notifySizeChanged = ((flag == 0) ? 0 : 1);
637 Window WMViewXID(WMView * view)
639 return view->window;
642 WMPoint WMGetViewScreenPosition(WMView * view)
644 WMScreen *scr = W_VIEW_SCREEN(view);
645 Window foo;
646 int x, y, topX, topY;
647 unsigned int bar;
648 WMView *topView;
650 topView = view;
651 while (topView->parent && topView->parent != scr->rootView)
652 topView = topView->parent;
654 if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX, &topY, &bar, &bar, &bar, &bar)) {
655 topX = topY = 0;
658 XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view), scr->rootWin, 0, 0, &x, &y, &foo);
660 return wmkpoint(x - topX, y - topY);
663 static void resizedParent(void *self, WMNotification * notif)
665 WMSize size = WMGetViewSize((WMView *) WMGetNotificationObject(notif));
666 WMView *view = (WMView *) self;
668 W_MoveView(view, view->leftOffs, view->topOffs);
669 W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
670 size.height - (view->topOffs + view->bottomOffs));
673 void WMSetViewExpandsToParent(WMView * view, int leftOffs, int topOffs, int rightOffs, int bottomOffs)
675 WMSize size = view->parent->size;
677 view->topOffs = topOffs;
678 view->bottomOffs = bottomOffs;
679 view->leftOffs = leftOffs;
680 view->rightOffs = rightOffs;
682 WMAddNotificationObserver(resizedParent, view, WMViewSizeDidChangeNotification, view->parent);
683 WMSetViewNotifySizeChanges(view->parent, True);
685 W_MoveView(view, leftOffs, topOffs);
686 W_ResizeView(view, size.width - (leftOffs + rightOffs), size.height - (topOffs + bottomOffs));