Fix periodic focus bug
[wmaker-crm.git] / WINGs / wview.c
blobbe840a9f3ca42b8dbf336fb68288785b8f2d46a7
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->xic = 0;
135 view->refCount = 1;
137 view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
139 return view;
144 W_View*
145 W_CreateView(W_View *parent)
147 return createView(parent->screen, parent);
151 W_View*
152 W_CreateRootView(W_Screen *screen)
154 W_View *view;
156 view = createView(screen, NULL);
158 view->window = screen->rootWin;
160 view->flags.realized = 1;
161 view->flags.mapped = 1;
162 view->flags.root = 1;
164 view->size.width =
165 WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
166 view->size.height =
167 HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
169 return view;
173 W_View*
174 W_CreateTopView(W_Screen *screen)
176 W_View *view;
178 view = createView(screen, screen->rootView);
179 if (!view)
180 return NULL;
182 view->flags.topLevel = 1;
183 view->attribs.event_mask |= StructureNotifyMask;
185 return view;
189 W_View*
190 W_CreateUnmanagedTopView(W_Screen *screen)
192 W_View *view;
194 view = createView(screen, screen->rootView);
195 if (!view)
196 return NULL;
198 view->flags.topLevel = 1;
199 view->attribs.event_mask |= StructureNotifyMask;
201 view->attribFlags |= CWOverrideRedirect;
202 view->attribs.override_redirect = True;
204 return view;
208 void
209 W_RealizeView(W_View *view)
211 Window parentWID;
212 Display *dpy = view->screen->display;
213 W_View *ptr;
215 assert(view->size.width > 0);
216 assert(view->size.height > 0);
218 if (view->parent && !view->parent->flags.realized) {
219 wwarning("trying to realize widget of unrealized parent");
220 return;
223 if (!view->flags.realized) {
224 parentWID = view->parent->window;
225 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
226 view->size.width, view->size.height, 0,
227 view->screen->depth, InputOutput,
228 view->screen->visual, view->attribFlags,
229 &view->attribs);
231 XSaveContext(dpy, view->window, ViewContext, (XPointer)view);
233 view->flags.realized = 1;
235 if (view->flags.mapWhenRealized) {
236 W_MapView(view);
237 view->flags.mapWhenRealized = 0;
240 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
243 /* realize children */
244 ptr = view->childrenList;
245 while (ptr!=NULL) {
246 W_RealizeView(ptr);
248 ptr = ptr->nextSister;
253 void
254 W_ReparentView(W_View *view, W_View *newParent, int x, int y)
256 Display *dpy = view->screen->display;
258 assert(!view->flags.topLevel);
260 unparentView(view);
261 adoptChildView(newParent, view);
263 if (view->flags.realized) {
264 if (newParent->flags.realized) {
265 XReparentWindow(dpy, view->window, newParent->window, x, y);
266 } else {
267 wwarning("trying to reparent realized view to unrealized parent");
268 return;
272 view->pos.x = x;
273 view->pos.y = y;
277 void
278 W_RaiseView(W_View *view)
280 if (W_VIEW_REALIZED(view))
281 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
286 void
287 W_LowerView(W_View *view)
289 if (W_VIEW_REALIZED(view))
290 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
295 void
296 W_MapView(W_View *view)
298 if (!view->flags.mapped) {
299 if (view->flags.realized) {
300 XMapRaised(view->screen->display, view->window);
301 XFlush(view->screen->display);
302 view->flags.mapped = 1;
303 } else {
304 view->flags.mapWhenRealized = 1;
311 * W_MapSubviews-
312 * maps all children of the current view that where already realized.
314 void
315 W_MapSubviews(W_View *view)
317 XMapSubwindows(view->screen->display, view->window);
318 XFlush(view->screen->display);
320 view = view->childrenList;
321 while (view) {
322 view->flags.mapped = 1;
323 view->flags.mapWhenRealized = 0;
324 view = view->nextSister;
330 void
331 W_UnmapSubviews(W_View *view)
333 XUnmapSubwindows(view->screen->display, view->window);
334 XFlush(view->screen->display);
336 view = view->childrenList;
337 while (view) {
338 view->flags.mapped = 0;
339 view->flags.mapWhenRealized = 0;
340 view = view->nextSister;
346 void
347 W_UnmapView(W_View *view)
349 view->flags.mapWhenRealized = 0;
350 if (!view->flags.mapped)
351 return;
353 XUnmapWindow(view->screen->display, view->window);
354 XFlush(view->screen->display);
356 view->flags.mapped = 0;
360 W_View*
361 W_TopLevelOfView(W_View *view)
363 W_View *toplevel;
365 for (toplevel=view;
366 toplevel && !toplevel->flags.topLevel;
367 toplevel=toplevel->parent);
369 return toplevel;
373 static void
374 destroyView(W_View *view)
376 W_View *ptr;
378 if (view->flags.alreadyDead)
379 return;
380 view->flags.alreadyDead = 1;
382 /* delete the balloon text for the view, if there's any */
383 WMSetBalloonTextForView(NULL, view);
385 if (view->nextFocusChain)
386 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
387 if (view->prevFocusChain)
388 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
390 /* Do not leave focus in a inexisting control */
391 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view))==view)
392 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
394 if (view->flags.topLevel) {
395 W_FocusInfo *info = view->screen->focusInfo;
396 /* remove focus information associated to this toplevel */
398 if (info) {
399 if (info->toplevel==view) {
400 view->screen->focusInfo = info->next;
401 wfree(info);
402 } else {
403 while (info->next) {
404 if (info->next->toplevel == view)
405 break;
406 info = info->next;
408 if (info->next) {
409 W_FocusInfo *next = info->next->next;
410 wfree(info->next);
411 info->next = next;
413 /* else the toplevel did not have any focused subview */
418 /* destroy children recursively */
419 while (view->childrenList!=NULL) {
420 ptr = view->childrenList;
421 ptr->flags.parentDying = 1;
423 W_DestroyView(ptr);
425 if (ptr == view->childrenList) {
426 view->childrenList = ptr->nextSister;
427 ptr->parent = NULL;
431 W_CallDestroyHandlers(view);
433 if (view->flags.realized) {
434 XDeleteContext(view->screen->display,
435 view->window, ViewContext);
437 /* if parent is being destroyed, it will die naturaly */
438 if (!view->flags.parentDying || view->flags.topLevel)
439 XDestroyWindow(view->screen->display, view->window);
442 /* remove self from parent's children list */
443 unparentView(view);
445 /* the array has a wfree() destructor that will be called automatically */
446 WMFreeArray(view->eventHandlers);
447 view->eventHandlers = NULL;
449 WMRemoveNotificationObserver(view);
451 W_FreeViewXdndPart(view);
453 if (view->backColor)
454 WMReleaseColor(view->backColor);
456 wfree(view);
461 void
462 W_DestroyView(W_View *view)
464 view->refCount--;
466 if (view->refCount < 1) {
467 destroyView(view);
473 void
474 W_MoveView(W_View *view, int x, int y)
476 assert(view->flags.root==0);
478 if (view->delegate && view->delegate->willMove) {
479 (*view->delegate->willMove)(view->delegate, view, &x, &y);
482 if (view->pos.x == x && view->pos.y == y)
483 return;
485 if (view->flags.realized) {
486 XMoveWindow(view->screen->display, view->window, x, y);
488 view->pos.x = x;
489 view->pos.y = y;
491 if (view->delegate && view->delegate->didMove) {
492 (*view->delegate->didMove)(view->delegate, view);
497 void
498 W_ResizeView(W_View *view, unsigned int width, unsigned int height)
500 /*int shrinked;*/
502 if (view->delegate && view->delegate->willResize) {
503 (*view->delegate->willResize)(view->delegate, view, &width, &height);
506 assert(width > 0);
507 assert(height > 0);
509 if (view->size.width == width && view->size.height == height)
510 return;
512 /*shrinked = width < view->size.width || height < view->size.height;*/
514 if (view->flags.realized) {
515 XResizeWindow(view->screen->display, view->window, width, height);
517 view->size.width = width;
518 view->size.height = height;
520 if (view->delegate && view->delegate->didResize) {
521 (*view->delegate->didResize)(view->delegate, view);
524 /* // TODO. replace in WINGs code, with the didResize delegate */
525 if (view->flags.notifySizeChanged)
526 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
530 void
531 W_RedisplayView(W_View *view)
533 XEvent ev;
535 if (!view->flags.mapped)
536 return;
538 ev.xexpose.type = Expose;
539 ev.xexpose.display = view->screen->display;
540 ev.xexpose.window = view->window;
541 ev.xexpose.count = 0;
543 ev.xexpose.serial = 0;
545 WMHandleEvent(&ev);
549 void
550 W_SetViewBackgroundColor(W_View *view, WMColor *color)
552 if (view->backColor)
553 WMReleaseColor(view->backColor);
554 view->backColor = WMRetainColor(color);
556 view->attribFlags |= CWBackPixel;
557 view->attribs.background_pixel = W_PIXEL(color);
558 if (view->flags.realized) {
559 XSetWindowBackground(view->screen->display, view->window,
560 W_PIXEL(color));
561 XClearWindow(view->screen->display, view->window);
566 void
567 W_SetViewCursor(W_View *view, Cursor cursor)
569 view->cursor = cursor;
570 if (W_VIEW_REALIZED(view)) {
571 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
572 } else {
573 view->attribFlags |= CWCursor;
574 view->attribs.cursor = cursor;
579 W_View*
580 W_FocusedViewOfToplevel(W_View *view)
582 WMScreen *scr = view->screen;
583 W_FocusInfo *info;
585 for (info = scr->focusInfo; info!=NULL; info = info->next)
586 if (view == info->toplevel)
587 break;
589 if (!info)
590 return NULL;
592 return info->focused;
596 void
597 W_SetFocusOfTopLevel(W_View *toplevel, W_View *view)
599 WMScreen *scr = toplevel->screen;
600 XEvent event;
601 W_FocusInfo *info;
603 for (info = scr->focusInfo; info!=NULL; info = info->next)
604 if (toplevel == info->toplevel)
605 break;
607 if (!info) {
608 info = wmalloc(sizeof(W_FocusInfo));
609 info->toplevel = toplevel;
610 info->focused = view;
611 info->next = scr->focusInfo;
612 scr->focusInfo = info;
613 } else {
614 event.xfocus.mode = NotifyNormal;
615 event.xfocus.detail = NotifyDetailNone;
616 if (info->focused) {
617 /* simulate FocusOut event */
618 event.xfocus.type = FocusOut;
619 W_DispatchMessage(info->focused, &event);
621 info->focused = view;
623 if (view) {
624 /* simulate FocusIn event */
625 event.xfocus.type = FocusIn;
626 W_DispatchMessage(view, &event);
631 void
632 W_BroadcastMessage(W_View *targetParent, XEvent *event)
634 W_View *target;
636 target = targetParent->childrenList;
637 while (target!=NULL) {
638 W_DispatchMessage(target, event);
640 target = target->nextSister;
645 void
646 W_DispatchMessage(W_View *target, XEvent *event)
648 if (target->window==None)
649 return;
650 event->xclient.window = target->window;
651 event->xclient.display = target->screen->display;
653 WMHandleEvent(event);
655 XSendEvent(target->screen->display, target->window, False,
656 SubstructureNotifyMask, event);
662 WMView*
663 W_RetainView(WMView *view)
665 view->refCount++;
667 return view;
671 void
672 W_ReleaseView(WMView *view)
674 view->refCount--;
676 if (view->refCount < 1) {
677 destroyView(view);
682 WMWidget*
683 WMWidgetOfView(WMView *view)
685 return view->self;
689 WMSize
690 WMGetViewSize(WMView *view)
692 return view->size;
695 WMPoint
696 WMGetViewPosition(WMView *view)
698 return view->pos;
702 void
703 WMSetViewNotifySizeChanges(WMView *view, Bool flag)
705 view->flags.notifySizeChanged = ((flag==0) ? 0 : 1);
709 Window
710 WMViewXID(WMView *view)
712 return view->window;
716 WMPoint
717 WMGetViewScreenPosition(WMView *view)
719 WMScreen *scr = W_VIEW_SCREEN(view);
720 Window foo;
721 int x, y, topX, topY;
722 unsigned int bar;
723 WMView *topView;
725 topView = view;
726 while (topView->parent && topView->parent!=scr->rootView)
727 topView = topView->parent;
729 if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX,
730 &topY, &bar, &bar, &bar, &bar)) {
731 topX = topY = 0;
734 XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view),
735 scr->rootWin, 0, 0, &x, &y, &foo);
737 return wmkpoint(x-topX, y-topY);
741 static void
742 resizedParent(void *self, WMNotification *notif)
744 WMSize size = WMGetViewSize((WMView*)WMGetNotificationObject(notif));
745 WMView *view = (WMView*)self;
747 W_MoveView(view, view->leftOffs, view->topOffs);
748 W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
749 size.height - (view->topOffs + view->bottomOffs));
753 void
754 WMSetViewExpandsToParent(WMView *view, int leftOffs, int topOffs,
755 int rightOffs, int bottomOffs)
757 WMSize size = view->parent->size;
759 view->topOffs = topOffs;
760 view->bottomOffs = bottomOffs;
761 view->leftOffs = leftOffs;
762 view->rightOffs = rightOffs;
764 WMAddNotificationObserver(resizedParent, view,
765 WMViewSizeDidChangeNotification,
766 view->parent);
767 WMSetViewNotifySizeChanges(view->parent, True);
769 W_MoveView(view, leftOffs, topOffs);
770 W_ResizeView(view, size.width - (leftOffs + rightOffs),
771 size.height - (topOffs + bottomOffs));