Radio and Check buttons now work
[wmaker-crm.git] / WINGs / wview.c
blob023cd07f2e86fca575094f113c51aef0ce596255
2 #include "WINGsP.h"
4 #include <cairo-xlib.h>
6 #include <X11/Xresource.h>
8 /* the notifications about views */
10 char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
11 char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
12 char *WMViewRealizedNotification = "WMViewRealizedNotification";
14 #define EVENT_MASK \
15 KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
16 EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
17 VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
18 SubstructureNotifyMask|SubstructureRedirectMask
20 static XSetWindowAttributes defAtts = {
21 None, /* background_pixmap */
22 0, /* background_pixel */
23 CopyFromParent, /* border_pixmap */
24 0, /* border_pixel */
25 ForgetGravity, /* bit_gravity */
26 ForgetGravity, /* win_gravity */
27 NotUseful, /* backing_store */
28 (unsigned)~0, /* backing_planes */
29 0, /* backing_pixel */
30 False, /* save_under */
31 EVENT_MASK, /* event_mask */
32 0, /* do_not_propagate_mask */
33 False, /* override_redirect */
34 None, /* colormap */
35 None /* cursor */
38 static XContext ViewContext = 0; /* context for views */
40 W_View *W_GetViewForXWindow(Display * display, Window window)
42 W_View *view;
44 if (XFindContext(display, window, ViewContext, (XPointer *) & view) == 0) {
45 return view;
47 return NULL;
50 static void unparentView(W_View * view)
52 /* remove from parent's children list */
53 if (view->parent != NULL) {
54 W_View *ptr;
56 ptr = view->parent->childrenList;
57 if (ptr == view) {
58 view->parent->childrenList = view->nextSister;
59 } else {
60 while (ptr != NULL) {
61 if (ptr->nextSister == view) {
62 ptr->nextSister = view->nextSister;
63 break;
65 ptr = ptr->nextSister;
69 view->parent = NULL;
72 static void adoptChildView(W_View * view, W_View * child)
74 child->nextSister = NULL;
76 /* add to end of children list of parent */
77 if (view->childrenList == NULL) {
78 view->childrenList = child;
79 } else {
80 W_View *ptr;
82 ptr = view->childrenList;
83 while (ptr->nextSister != NULL)
84 ptr = ptr->nextSister;
85 ptr->nextSister = child;
87 child->parent = view;
90 static W_View *createView(W_Screen * screen, W_View * parent)
92 W_View *view;
94 if (ViewContext == 0)
95 ViewContext = XUniqueContext();
97 view = wmalloc(sizeof(W_View));
98 memset(view, 0, sizeof(W_View));
100 view->screen = screen;
102 view->backColor= WMGrayColorSpec();
104 if (parent!=NULL) {
105 XColor xcolor;
106 xcolor.red = view->backColor.red << 8;
107 xcolor.green = view->backColor.green << 8;
108 xcolor.blue = view->backColor.blue << 8;
109 xcolor.flags = DoRed | DoGreen | DoBlue;
110 XAllocColor(screen->display,screen->colormap,&xcolor);
112 /* attributes are not valid for root window */
113 view->attribFlags = CWEventMask|CWBitGravity;
114 view->attribs = defAtts;
116 view->attribFlags |= CWBackPixel|CWColormap|CWBorderPixel;
117 view->attribs.background_pixel = xcolor.pixel;
118 view->attribs.border_pixel = 0;
119 view->attribs.colormap = screen->colormap;
121 adoptChildView(parent, view);
124 view->xic = 0;
126 view->refCount = 1;
128 view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
130 return view;
133 W_View *W_CreateView(W_View * parent)
135 return createView(parent->screen, parent);
138 W_View *W_CreateRootView(W_Screen * screen)
140 W_View *view;
142 view = createView(screen, NULL);
144 view->window = screen->rootWin;
146 view->flags.realized = 1;
147 view->flags.mapped = 1;
148 view->flags.root = 1;
150 view->size.width = WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
151 view->size.height = HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
153 return view;
156 W_View *W_CreateTopView(W_Screen * screen)
158 W_View *view;
160 view = createView(screen, screen->rootView);
161 if (!view)
162 return NULL;
164 view->flags.topLevel = 1;
165 view->attribs.event_mask |= StructureNotifyMask;
167 return view;
170 W_View *W_CreateUnmanagedTopView(W_Screen * screen)
172 W_View *view;
174 view = createView(screen, screen->rootView);
175 if (!view)
176 return NULL;
178 view->flags.topLevel = 1;
179 view->attribs.event_mask |= StructureNotifyMask;
181 view->attribFlags |= CWOverrideRedirect;
182 view->attribs.override_redirect = True;
184 return view;
187 void W_RealizeView(W_View * view)
189 Window parentWID;
190 Display *dpy = view->screen->display;
191 W_View *ptr;
193 assert(view->size.width > 0);
194 assert(view->size.height > 0);
196 if (view->parent && !view->parent->flags.realized) {
197 wwarning("trying to realize widget of unrealized parent");
198 return;
201 if (!view->flags.realized) {
202 parentWID = view->parent->window;
203 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
204 view->size.width, view->size.height, 0,
205 view->screen->depth, InputOutput,
206 view->screen->visual, view->attribFlags, &view->attribs);
208 XSaveContext(dpy, view->window, ViewContext, (XPointer) view);
210 view->flags.realized = 1;
212 if (view->flags.mapWhenRealized) {
213 W_MapView(view);
214 view->flags.mapWhenRealized = 0;
217 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
220 /* realize children */
221 ptr = view->childrenList;
222 while (ptr != NULL) {
223 W_RealizeView(ptr);
225 ptr = ptr->nextSister;
229 void W_ReparentView(W_View * view, W_View * newParent, int x, int y)
231 Display *dpy = view->screen->display;
233 assert(!view->flags.topLevel);
235 unparentView(view);
236 adoptChildView(newParent, view);
237 if (view->flags.realized) {
238 if (newParent->flags.realized) {
239 XReparentWindow(dpy, view->window, newParent->window, x, y);
240 } else {
241 wwarning("trying to reparent realized view to unrealized parent");
242 return;
246 view->pos.x = x;
247 view->pos.y = y;
250 void W_RaiseView(W_View * view)
252 if (W_VIEW_REALIZED(view))
253 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
256 void W_LowerView(W_View * view)
258 if (W_VIEW_REALIZED(view))
259 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
262 void W_MapView(W_View * view)
264 if (!view->flags.mapped) {
265 if (view->flags.realized) {
266 XMapRaised(view->screen->display, view->window);
267 XFlush(view->screen->display);
268 view->flags.mapped = 1;
269 } else {
270 view->flags.mapWhenRealized = 1;
276 * W_MapSubviews-
277 * maps all children of the current view that where already realized.
279 void W_MapSubviews(W_View * view)
281 XMapSubwindows(view->screen->display, view->window);
282 XFlush(view->screen->display);
284 view = view->childrenList;
285 while (view) {
286 view->flags.mapped = 1;
287 view->flags.mapWhenRealized = 0;
288 view = view->nextSister;
292 void W_UnmapSubviews(W_View * view)
294 XUnmapSubwindows(view->screen->display, view->window);
295 XFlush(view->screen->display);
297 view = view->childrenList;
298 while (view) {
299 view->flags.mapped = 0;
300 view->flags.mapWhenRealized = 0;
301 view = view->nextSister;
305 void W_UnmapView(W_View * view)
307 view->flags.mapWhenRealized = 0;
308 if (!view->flags.mapped)
309 return;
311 XUnmapWindow(view->screen->display, view->window);
312 XFlush(view->screen->display);
314 view->flags.mapped = 0;
317 W_View *W_TopLevelOfView(W_View * view)
319 W_View *toplevel;
321 for (toplevel = view; toplevel && !toplevel->flags.topLevel; toplevel = toplevel->parent) ;
323 return toplevel;
326 static void destroyView(W_View * view)
328 W_View *ptr;
330 if (view->flags.alreadyDead)
331 return;
332 view->flags.alreadyDead = 1;
334 /* delete the balloon text for the view, if there's any */
335 WMSetBalloonTextForView(NULL, view);
337 if (view->nextFocusChain)
338 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
339 if (view->prevFocusChain)
340 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
342 /* Do not leave focus in a inexisting control */
343 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view)) == view)
344 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
346 if (view->flags.topLevel) {
347 W_FocusInfo *info = view->screen->focusInfo;
348 /* remove focus information associated to this toplevel */
350 if (info) {
351 if (info->toplevel == view) {
352 view->screen->focusInfo = info->next;
353 wfree(info);
354 } else {
355 while (info->next) {
356 if (info->next->toplevel == view)
357 break;
358 info = info->next;
360 if (info->next) {
361 W_FocusInfo *next = info->next->next;
362 wfree(info->next);
363 info->next = next;
365 /* else the toplevel did not have any focused subview */
370 /* destroy children recursively */
371 while (view->childrenList != NULL) {
372 ptr = view->childrenList;
373 ptr->flags.parentDying = 1;
375 W_DestroyView(ptr);
377 if (ptr == view->childrenList) {
378 view->childrenList = ptr->nextSister;
379 ptr->parent = NULL;
384 W_CallDestroyHandlers(view);
386 if (view->flags.realized) {
387 XDeleteContext(view->screen->display, view->window, ViewContext);
389 /* if parent is being destroyed, it will die naturaly */
390 if (!view->flags.parentDying || view->flags.topLevel)
391 XDestroyWindow(view->screen->display, view->window);
394 /* remove self from parent's children list */
395 unparentView(view);
397 /* the array has a wfree() destructor that will be called automatically */
398 WMFreeArray(view->eventHandlers);
399 view->eventHandlers = NULL;
401 WMRemoveNotificationObserver(view);
403 W_FreeViewXdndPart(view);
405 wfree(view);
408 cairo_t* W_CreateCairoForView(W_View *view)
410 cairo_surface_t *surface;
411 cairo_t *cairo;
413 surface = cairo_xlib_surface_create(W_VIEW_DISPLAY(view),
414 W_VIEW_DRAWABLE(view),
415 W_VIEW_SCREEN(view)->visual,
416 W_VIEW_WIDTH(view),
417 W_VIEW_HEIGHT(view));
418 cairo = cairo_create(surface);
419 cairo_surface_destroy(surface);
420 cairo_translate(cairo, 0.5, 0.5);
421 cairo_set_line_width(cairo, 1.0);
423 return cairo;
426 void W_DestroyView(W_View * view)
428 view->refCount--;
430 if (view->refCount < 1) {
431 destroyView(view);
435 void W_MoveView(W_View * view, int x, int y)
437 assert(view->flags.root == 0);
439 if (view->delegate && view->delegate->willMove) {
440 (*view->delegate->willMove) (view->delegate, view, &x, &y);
443 if (view->pos.x == x && view->pos.y == y)
444 return;
446 if (view->flags.realized) {
447 XMoveWindow(view->screen->display, view->window, x, y);
449 view->pos.x = x;
450 view->pos.y = y;
452 if (view->delegate && view->delegate->didMove) {
453 (*view->delegate->didMove) (view->delegate, view);
457 void W_ResizeView(W_View * view, unsigned int width, unsigned int height)
459 /*int shrinked; */
461 if (view->delegate && view->delegate->willResize) {
462 (*view->delegate->willResize) (view->delegate, view, &width, &height);
465 assert(width > 0);
466 assert(height > 0);
468 if (view->size.width == width && view->size.height == height)
469 return;
471 /*shrinked = width < view->size.width || height < view->size.height; */
473 if (view->flags.realized) {
474 XResizeWindow(view->screen->display, view->window, width, height);
476 view->size.width = width;
477 view->size.height = height;
479 if (view->delegate && view->delegate->didResize) {
480 (*view->delegate->didResize) (view->delegate, view);
483 /* // TODO. replace in WINGs code, with the didResize delegate */
484 if (view->flags.notifySizeChanged)
485 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
488 void W_RedisplayView(W_View * view)
490 XEvent ev;
492 if (!view->flags.mapped)
493 return;
495 ev.xexpose.type = Expose;
496 ev.xexpose.display = view->screen->display;
497 ev.xexpose.window = view->window;
498 ev.xexpose.count = 0;
500 ev.xexpose.serial = 0;
502 WMHandleEvent(&ev);
505 void W_SetViewBackgroundColor(W_View *view, WMColorSpec *color)
507 // XColor xcolor= WMCreateColorWithSpec(view->screen, color);
509 // view->backColor = *color;
511 // view->attribFlags |= CWBackPixel;
512 // view->attribs.background_pixel = W_PIXEL(xcolor);
513 // if (view->flags.realized) {
514 // XSetWindowBackground(view->screen->display, view->window,
515 // W_PIXEL(xcolor));
516 // XClearWindow(view->screen->display, view->window);
517 // }
518 // WMReleaseColor(xcolor);
521 void W_SetViewCursor(W_View * view, Cursor cursor)
523 view->cursor = cursor;
524 if (W_VIEW_REALIZED(view)) {
525 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
526 } else {
527 view->attribFlags |= CWCursor;
528 view->attribs.cursor = cursor;
532 W_View *W_FocusedViewOfToplevel(W_View * view)
534 WMScreen *scr = view->screen;
535 W_FocusInfo *info;
537 for (info = scr->focusInfo; info != NULL; info = info->next)
538 if (view == info->toplevel)
539 break;
541 if (!info)
542 return NULL;
544 return info->focused;
547 void W_SetFocusOfTopLevel(W_View * toplevel, W_View * view)
549 WMScreen *scr = toplevel->screen;
550 XEvent event;
551 W_FocusInfo *info;
553 for (info = scr->focusInfo; info != NULL; info = info->next)
554 if (toplevel == info->toplevel)
555 break;
557 if (!info) {
558 info = wmalloc(sizeof(W_FocusInfo));
559 info->toplevel = toplevel;
560 info->focused = view;
561 info->next = scr->focusInfo;
562 scr->focusInfo = info;
563 } else {
564 event.xfocus.mode = NotifyNormal;
565 event.xfocus.detail = NotifyDetailNone;
566 if (info->focused) {
567 /* simulate FocusOut event */
568 event.xfocus.type = FocusOut;
569 W_DispatchMessage(info->focused, &event);
571 info->focused = view;
573 if (view) {
574 /* simulate FocusIn event */
575 event.xfocus.type = FocusIn;
576 W_DispatchMessage(view, &event);
580 void W_BroadcastMessage(W_View * targetParent, XEvent * event)
582 W_View *target;
584 target = targetParent->childrenList;
585 while (target != NULL) {
586 W_DispatchMessage(target, event);
588 target = target->nextSister;
592 void W_DispatchMessage(W_View * target, XEvent * event)
594 if (target->window == None)
595 return;
596 event->xclient.window = target->window;
597 event->xclient.display = target->screen->display;
599 WMHandleEvent(event);
601 XSendEvent(target->screen->display, target->window, False,
602 SubstructureNotifyMask, event);
606 WMView *W_RetainView(WMView * view)
608 view->refCount++;
610 return view;
613 void W_ReleaseView(WMView * view)
615 view->refCount--;
617 if (view->refCount < 1) {
618 destroyView(view);
622 WMWidget *WMWidgetOfView(WMView * view)
624 return view->self;
627 WMSize WMGetViewSize(WMView * view)
629 return view->size;
632 WMPoint WMGetViewPosition(WMView * view)
634 return view->pos;
637 void WMSetViewNotifySizeChanges(WMView * view, Bool flag)
639 view->flags.notifySizeChanged = ((flag == 0) ? 0 : 1);
642 Window WMViewXID(WMView * view)
644 return view->window;
647 WMPoint WMGetViewScreenPosition(WMView * view)
649 WMScreen *scr = W_VIEW_SCREEN(view);
650 Window foo;
651 int x, y, topX, topY;
652 unsigned int bar;
653 WMView *topView;
655 topView = view;
656 while (topView->parent && topView->parent != scr->rootView)
657 topView = topView->parent;
659 if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX, &topY, &bar, &bar, &bar, &bar)) {
660 topX = topY = 0;
663 XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view), scr->rootWin, 0, 0, &x, &y, &foo);
665 return wmkpoint(x - topX, y - topY);
668 static void resizedParent(void *self, WMNotification * notif)
670 WMSize size = WMGetViewSize((WMView *) WMGetNotificationObject(notif));
671 WMView *view = (WMView *) self;
673 W_MoveView(view, view->leftOffs, view->topOffs);
674 W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
675 size.height - (view->topOffs + view->bottomOffs));
678 void WMSetViewExpandsToParent(WMView * view, int leftOffs, int topOffs, int rightOffs, int bottomOffs)
680 WMSize size = view->parent->size;
682 view->topOffs = topOffs;
683 view->bottomOffs = bottomOffs;
684 view->leftOffs = leftOffs;
685 view->rightOffs = rightOffs;
687 WMAddNotificationObserver(resizedParent, view, WMViewSizeDidChangeNotification, view->parent);
688 WMSetViewNotifySizeChanges(view->parent, True);
690 W_MoveView(view, leftOffs, topOffs);
691 W_ResizeView(view, size.width - (leftOffs + rightOffs), size.height - (topOffs + bottomOffs));