- Updated WINGs/NEWS with info about hw the API changed how how things
[wmaker-crm.git] / WINGs / wview.c
blob05ab00099d0d1bafed37988e5230aa5a54ecda2d
3 #include "WINGsP.h"
5 #include <X11/Xresource.h>
9 /* the notifications about views */
11 char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
12 char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
13 char *WMViewRealizedNotification = "WMViewRealizedNotification";
16 #define EVENT_MASK \
17 KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
18 EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
19 VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
20 SubstructureNotifyMask|SubstructureRedirectMask
23 static XSetWindowAttributes defAtts= {
24 None, /* background_pixmap */
25 0, /* background_pixel */
26 CopyFromParent, /* border_pixmap */
27 0, /* border_pixel */
28 ForgetGravity, /* bit_gravity */
29 ForgetGravity, /* win_gravity */
30 NotUseful, /* backing_store */
31 (unsigned) ~0, /* backing_planes */
32 0, /* backing_pixel */
33 False, /* save_under */
34 EVENT_MASK, /* event_mask */
35 0, /* do_not_propagate_mask */
36 False, /* override_redirect */
37 None, /* colormap */
38 None /* cursor */
43 static XContext ViewContext=0; /* context for views */
48 W_View*
49 W_GetViewForXWindow(Display *display, Window window)
51 W_View *view;
53 if (XFindContext(display, window, ViewContext, (XPointer*)&view)==0) {
54 return view;
56 return NULL;
61 static void
62 unparentView(W_View *view)
64 /* remove from parent's children list */
65 if (view->parent!=NULL) {
66 W_View *ptr;
68 ptr = view->parent->childrenList;
69 if (ptr == view) {
70 view->parent->childrenList = view->nextSister;
71 } else {
72 while (ptr!=NULL) {
73 if (ptr->nextSister == view) {
74 ptr->nextSister = view->nextSister;
75 break;
77 ptr = ptr->nextSister;
81 view->parent = NULL;
85 static void
86 adoptChildView(W_View *view, W_View *child)
88 child->nextSister = NULL;
90 /* add to end of children list of parent */
91 if (view->childrenList == NULL) {
92 view->childrenList = child;
93 } else {
94 W_View *ptr;
96 ptr = view->childrenList;
97 while (ptr->nextSister!=NULL)
98 ptr = ptr->nextSister;
99 ptr->nextSister = child;
101 child->parent = view;
105 static W_View*
106 createView(W_Screen *screen, W_View *parent)
108 W_View *view;
110 if (ViewContext==0)
111 ViewContext = XUniqueContext();
113 view = wmalloc(sizeof(W_View));
114 memset(view, 0, sizeof(W_View));
116 view->screen = screen;
118 if (parent!=NULL) {
119 /* attributes are not valid for root window */
120 view->attribFlags = CWEventMask|CWBitGravity;
121 view->attribs = defAtts;
123 view->attribFlags |= CWBackPixel|CWColormap|CWBorderPixel;
124 view->attribs.background_pixel = W_PIXEL(screen->gray);
125 view->attribs.border_pixel = W_PIXEL(screen->black);
126 view->attribs.colormap = screen->colormap;
128 view->backColor = WMRetainColor(screen->gray);
130 adoptChildView(parent, view);
133 view->refCount = 1;
135 view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
137 return view;
142 W_View*
143 W_CreateView(W_View *parent)
145 return createView(parent->screen, parent);
149 W_View*
150 W_CreateRootView(W_Screen *screen)
152 W_View *view;
154 view = createView(screen, NULL);
156 view->window = screen->rootWin;
158 view->flags.realized = 1;
159 view->flags.mapped = 1;
160 view->flags.root = 1;
162 view->size.width =
163 WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
164 view->size.height =
165 HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
167 return view;
171 W_View*
172 W_CreateTopView(W_Screen *screen)
174 W_View *view;
176 view = createView(screen, screen->rootView);
177 if (!view)
178 return NULL;
180 view->flags.topLevel = 1;
181 view->attribs.event_mask |= StructureNotifyMask;
183 return view;
187 W_View*
188 W_CreateUnmanagedTopView(W_Screen *screen)
190 W_View *view;
192 view = createView(screen, screen->rootView);
193 if (!view)
194 return NULL;
196 view->flags.topLevel = 1;
197 view->attribs.event_mask |= StructureNotifyMask;
199 view->attribFlags |= CWOverrideRedirect;
200 view->attribs.override_redirect = True;
202 return view;
206 void
207 W_RealizeView(W_View *view)
209 Window parentWID;
210 Display *dpy = view->screen->display;
211 W_View *ptr;
213 assert(view->size.width > 0);
214 assert(view->size.height > 0);
217 if (view->parent && !view->parent->flags.realized) {
218 wwarning("trying to realize widget of unrealized parent");
219 return;
222 if (!view->flags.realized) {
223 parentWID = view->parent->window;
224 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
225 view->size.width, view->size.height, 0,
226 view->screen->depth, InputOutput,
227 view->screen->visual, view->attribFlags,
228 &view->attribs);
230 XSaveContext(dpy, view->window, ViewContext, (XPointer)view);
232 view->flags.realized = 1;
234 if (view->flags.mapWhenRealized) {
235 W_MapView(view);
236 view->flags.mapWhenRealized = 0;
239 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
242 /* realize children */
243 ptr = view->childrenList;
244 while (ptr!=NULL) {
245 W_RealizeView(ptr);
247 ptr = ptr->nextSister;
252 void
253 W_ReparentView(W_View *view, W_View *newParent, int x, int y)
255 Display *dpy = view->screen->display;
257 assert(!view->flags.topLevel);
259 unparentView(view);
260 adoptChildView(newParent, view);
262 if (view->flags.realized) {
263 if (newParent->flags.realized) {
264 XReparentWindow(dpy, view->window, newParent->window, x, y);
265 } else {
266 wwarning("trying to reparent realized view to unrealized parent");
267 return;
271 view->pos.x = x;
272 view->pos.y = y;
276 void
277 W_RaiseView(W_View *view)
279 if (W_VIEW_REALIZED(view))
280 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
285 void
286 W_LowerView(W_View *view)
288 if (W_VIEW_REALIZED(view))
289 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
294 void
295 W_MapView(W_View *view)
297 if (!view->flags.mapped) {
298 if (view->flags.realized) {
299 XMapRaised(view->screen->display, view->window);
300 XFlush(view->screen->display);
301 view->flags.mapped = 1;
302 } else {
303 view->flags.mapWhenRealized = 1;
310 * W_MapSubviews-
311 * maps all children of the current view that where already realized.
313 void
314 W_MapSubviews(W_View *view)
316 XMapSubwindows(view->screen->display, view->window);
317 XFlush(view->screen->display);
319 view = view->childrenList;
320 while (view) {
321 view->flags.mapped = 1;
322 view->flags.mapWhenRealized = 0;
323 view = view->nextSister;
329 void
330 W_UnmapSubviews(W_View *view)
332 XUnmapSubwindows(view->screen->display, view->window);
333 XFlush(view->screen->display);
335 view = view->childrenList;
336 while (view) {
337 view->flags.mapped = 0;
338 view->flags.mapWhenRealized = 0;
339 view = view->nextSister;
345 void
346 W_UnmapView(W_View *view)
348 view->flags.mapWhenRealized = 0;
349 if (!view->flags.mapped)
350 return;
352 XUnmapWindow(view->screen->display, view->window);
353 XFlush(view->screen->display);
355 view->flags.mapped = 0;
359 W_View*
360 W_TopLevelOfView(W_View *view)
362 W_View *toplevel;
364 for (toplevel=view;
365 toplevel && !toplevel->flags.topLevel;
366 toplevel=toplevel->parent);
368 return toplevel;
372 static void
373 destroyView(W_View *view)
375 W_View *ptr;
377 if (view->flags.alreadyDead)
378 return;
379 view->flags.alreadyDead = 1;
381 /* delete the balloon text for the view, if there's any */
382 WMSetBalloonTextForView(NULL, view);
384 if (view->nextFocusChain)
385 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
386 if (view->prevFocusChain)
387 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
389 /* Do not leave focus in a inexisting control */
390 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view))==view)
391 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
393 if (view->flags.topLevel) {
394 W_FocusInfo *info = view->screen->focusInfo;
395 /* remove focus information associated to this toplevel */
397 if (info) {
398 if (info->toplevel==view) {
399 view->screen->focusInfo = info->next;
400 wfree(info);
401 } else {
402 while (info->next) {
403 if (info->next->toplevel == view)
404 break;
405 info = info->next;
407 if (info->next) {
408 W_FocusInfo *next = info->next->next;
409 wfree(info->next);
410 info->next = next;
412 /* else the toplevel did not have any focused subview */
417 /* destroy children recursively */
418 while (view->childrenList!=NULL) {
419 ptr = view->childrenList;
420 ptr->flags.parentDying = 1;
422 W_DestroyView(ptr);
424 if (ptr == view->childrenList) {
425 view->childrenList = ptr->nextSister;
426 ptr->parent = NULL;
430 W_CallDestroyHandlers(view);
432 if (view->flags.realized) {
433 XDeleteContext(view->screen->display,
434 view->window, ViewContext);
436 /* if parent is being destroyed, it will die naturaly */
437 if (!view->flags.parentDying || view->flags.topLevel)
438 XDestroyWindow(view->screen->display, view->window);
441 /* remove self from parent's children list */
442 unparentView(view);
444 /* the array has a wfree() destructor that will be called automatically */
445 WMFreeArray(view->eventHandlers);
446 view->eventHandlers = NULL;
448 WMUnregisterViewDraggedTypes(view);
450 WMRemoveNotificationObserver(view);
452 #if 0
453 if (view->dragSourceProcs)
454 wfree(view->dragSourceProcs);
456 if (view->dragDestinationProcs)
457 wfree(view->dragDestinationProcs);
459 if (scr->dragInfo.destView == view) {
460 scr->dragInfo.destView = NULL;
462 #endif
463 wfree(view);
468 void
469 W_DestroyView(W_View *view)
471 view->refCount--;
473 if (view->refCount < 1) {
474 destroyView(view);
480 void
481 W_MoveView(W_View *view, int x, int y)
483 assert(view->flags.root==0);
484 //TODO move this after the test pos==oldpos
485 if (view->delegate && view->delegate->willMove) {
486 (*view->delegate->willMove)(view->delegate, view, &x, &y);
489 if (view->pos.x == x && view->pos.y == y)
490 return;
492 if (view->flags.realized) {
493 XMoveWindow(view->screen->display, view->window, x, y);
495 view->pos.x = x;
496 view->pos.y = y;
498 if (view->delegate && view->delegate->didMove) {
499 (*view->delegate->didMove)(view->delegate, view);
504 void
505 W_ResizeView(W_View *view, unsigned int width, unsigned int height)
507 int shrinked;
508 // TODO move this after the test size==oldsize
509 if (view->delegate && view->delegate->willResize) {
510 (*view->delegate->willResize)(view->delegate, view, &width, &height);
513 assert(width > 0);
514 assert(height > 0);
516 if (view->size.width == width && view->size.height == height)
517 return;
519 shrinked = width < view->size.width || height < view->size.height;
521 if (view->flags.realized) {
522 XResizeWindow(view->screen->display, view->window, width, height);
524 view->size.width = width;
525 view->size.height = height;
527 if (view->delegate && view->delegate->didResize) {
528 (*view->delegate->didResize)(view->delegate, view);
531 if (view->flags.notifySizeChanged)
532 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
536 void
537 W_RedisplayView(W_View *view)
539 XEvent ev;
541 if (!view->flags.mapped)
542 return;
544 ev.xexpose.type = Expose;
545 ev.xexpose.display = view->screen->display;
546 ev.xexpose.window = view->window;
547 ev.xexpose.count = 0;
549 ev.xexpose.serial = 0;
551 WMHandleEvent(&ev);
555 void
556 W_SetViewBackgroundColor(W_View *view, WMColor *color)
558 if (view->backColor)
559 WMReleaseColor(view->backColor);
560 view->backColor = WMRetainColor(color);
562 view->attribFlags |= CWBackPixel;
563 view->attribs.background_pixel = W_PIXEL(color);
564 if (view->flags.realized) {
565 XSetWindowBackground(view->screen->display, view->window,
566 W_PIXEL(color));
567 XClearWindow(view->screen->display, view->window);
572 void
573 W_SetViewCursor(W_View *view, Cursor cursor)
575 view->cursor = cursor;
576 if (W_VIEW_REALIZED(view)) {
577 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
578 } else {
579 view->attribFlags |= CWCursor;
580 view->attribs.cursor = cursor;
585 W_View*
586 W_FocusedViewOfToplevel(W_View *view)
588 WMScreen *scr = view->screen;
589 W_FocusInfo *info;
591 for (info = scr->focusInfo; info!=NULL; info = info->next)
592 if (view == info->toplevel)
593 break;
595 if (!info)
596 return NULL;
598 return info->focused;
602 void
603 W_SetFocusOfTopLevel(W_View *toplevel, W_View *view)
605 WMScreen *scr = toplevel->screen;
606 XEvent event;
607 W_FocusInfo *info;
609 for (info = scr->focusInfo; info!=NULL; info = info->next)
610 if (toplevel == info->toplevel)
611 break;
613 if (!info) {
614 info = wmalloc(sizeof(W_FocusInfo));
615 info->toplevel = toplevel;
616 info->focused = view;
617 info->next = scr->focusInfo;
618 scr->focusInfo = info;
619 } else {
620 event.xfocus.mode = NotifyNormal;
621 event.xfocus.detail = NotifyDetailNone;
622 if (info->focused) {
623 /* simulate FocusOut event */
624 event.xfocus.type = FocusOut;
625 W_DispatchMessage(info->focused, &event);
627 info->focused = view;
629 if (view) {
630 /* simulate FocusIn event */
631 event.xfocus.type = FocusIn;
632 W_DispatchMessage(view, &event);
637 void
638 W_BroadcastMessage(W_View *targetParent, XEvent *event)
640 W_View *target;
642 target = targetParent->childrenList;
643 while (target!=NULL) {
644 W_DispatchMessage(target, event);
646 target = target->nextSister;
651 void
652 W_DispatchMessage(W_View *target, XEvent *event)
654 if (target->window==None)
655 return;
656 event->xclient.window = target->window;
657 event->xclient.display = target->screen->display;
659 WMHandleEvent(event);
661 XSendEvent(target->screen->display, target->window, False,
662 SubstructureNotifyMask, event);
668 WMView*
669 W_RetainView(WMView *view)
671 view->refCount++;
673 return view;
677 void
678 W_ReleaseView(WMView *view)
680 view->refCount--;
682 if (view->refCount < 1) {
683 destroyView(view);
688 WMWidget*
689 WMWidgetOfView(WMView *view)
691 return view->self;
695 WMSize
696 WMGetViewSize(WMView *view)
698 return view->size;
701 WMPoint
702 WMGetViewPosition(WMView *view)
704 return view->pos;
708 void
709 WMSetViewNotifySizeChanges(WMView *view, Bool flag)
711 view->flags.notifySizeChanged = ((flag==0) ? 0 : 1);
715 Window
716 WMViewXID(WMView *view)
718 return view->window;
722 WMPoint
723 WMGetViewScreenPosition(WMView *view)
725 WMScreen *scr = W_VIEW_SCREEN(view);
726 Window foo;
727 int x, y, topX, topY, bar;
728 WMView *topView;
730 topView = view;
731 while (topView->parent && topView->parent!=scr->rootView)
732 topView = topView->parent;
734 if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX,
735 &topY, &bar, &bar, &bar, &bar)) {
736 topX = topY = 0;
739 XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view),
740 scr->rootWin, 0, 0, &x, &y, &foo);
742 return wmkpoint(x-topX, y-topY);
746 static void
747 resizedParent(void *self, WMNotification *notif)
749 WMSize size = WMGetViewSize((WMView*)WMGetNotificationObject(notif));
750 WMView *view = (WMView*)self;
752 W_MoveView(view, view->leftOffs, view->topOffs);
753 W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
754 size.height - (view->topOffs + view->bottomOffs));
758 void
759 WMSetViewExpandsToParent(WMView *view, int leftOffs, int topOffs,
760 int rightOffs, int bottomOffs)
762 WMSize size = view->parent->size;
764 view->topOffs = topOffs;
765 view->bottomOffs = bottomOffs;
766 view->leftOffs = leftOffs;
767 view->rightOffs = rightOffs;
769 WMAddNotificationObserver(resizedParent, view,
770 WMViewSizeDidChangeNotification,
771 view->parent);
772 WMSetViewNotifySizeChanges(view->parent, True);
774 W_MoveView(view, leftOffs, topOffs);
775 W_ResizeView(view, size.width - (leftOffs + rightOffs),
776 size.height - (topOffs + bottomOffs));