Initial revision
[wmaker-crm.git] / WINGs / wview.c
blob4d1956af369d7c0f2df7d7d604fd5b80701be6ea
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;
106 static void
107 handleEvents(XEvent *event, void *data)
109 W_View *view = (W_View*)data;
111 if (event->type == ConfigureNotify) {
113 if (event->xconfigure.width != view->size.width
114 || event->xconfigure.height != view->size.height) {
116 if (view->flags.notifySizeChanged) {
117 view->size.width = event->xconfigure.width;
118 view->size.height = event->xconfigure.height;
119 WMPostNotificationName(WMViewSizeDidChangeNotification,
120 view, NULL);
127 static W_View*
128 createView(W_Screen *screen, W_View *parent)
130 W_View *view;
132 if (ViewContext==0)
133 ViewContext = XUniqueContext();
135 view = wmalloc(sizeof(W_View));
136 memset(view, 0, sizeof(W_View));
138 view->refCount = 1;
140 view->screen = screen;
142 if (parent!=NULL) {
143 /* attributes are not valid for root window */
144 view->attribFlags = CWEventMask|CWBitGravity;
145 view->attribs = defAtts;
147 view->attribFlags |= CWBackPixel|CWColormap;
148 view->attribs.background_pixel = W_PIXEL(screen->gray);
149 view->attribs.colormap = screen->colormap;
151 adoptChildView(parent, view);
154 return view;
159 W_View*
160 W_CreateView(W_View *parent)
162 return createView(parent->screen, parent);
166 W_View*
167 W_CreateRootView(W_Screen *screen)
169 W_View *view;
171 view = createView(screen, NULL);
173 view->window = screen->rootWin;
175 view->flags.realized = 1;
176 view->flags.mapped = 1;
177 view->flags.root = 1;
179 view->size.width =
180 WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
181 view->size.height =
182 HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
184 return view;
188 W_View*
189 W_CreateTopView(W_Screen *screen)
191 W_View *view;
193 view = createView(screen, screen->rootView);
194 if (!view)
195 return NULL;
197 view->flags.topLevel = 1;
198 view->attribs.event_mask |= StructureNotifyMask;
200 /* catch changes in the toplevel window (resize from user etc.) */
201 WMCreateEventHandler(view, StructureNotifyMask, handleEvents, view);
203 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);
219 if (view->parent && !view->parent->flags.realized) {
220 wwarning("trying to realize widget of unrealized parent");
221 return;
224 if (!view->flags.realized) {
225 parentWID = view->parent->window;
226 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
227 view->size.width, view->size.height, 0,
228 view->screen->depth, InputOutput,
229 view->screen->visual, view->attribFlags,
230 &view->attribs);
232 XSaveContext(dpy, view->window, ViewContext, (XPointer)view);
234 view->flags.realized = 1;
236 if (view->flags.mapWhenRealized) {
237 W_MapView(view);
238 view->flags.mapWhenRealized = 0;
241 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
244 /* realize children */
245 ptr = view->childrenList;
246 while (ptr!=NULL) {
247 W_RealizeView(ptr);
249 ptr = ptr->nextSister;
255 Bool
256 W_CheckInternalMessage(W_Screen *scr, XClientMessageEvent *cev, int event)
258 if (cev->message_type == scr->internalMessage
259 && cev->format == 32 && cev->data.l[1] == event)
260 return True;
261 else
262 return False;
266 void
267 W_ReparentView(W_View *view, W_View *newParent)
269 int wasMapped;
270 Display *dpy = view->screen->display;
272 assert(!view->flags.topLevel);
274 wasMapped = view->flags.mapped;
275 if (wasMapped)
276 W_UnmapView(view);
278 unparentView(view);
279 adoptChildView(newParent, view);
281 if (view->flags.realized) {
282 if (newParent->flags.realized) {
283 XReparentWindow(dpy, view->window, newParent->window, 0, 0);
284 } else {
285 wwarning("trying to reparent realized view to unrealized parent");
286 return;
290 view->pos.x = 0;
291 view->pos.y = 0;
293 if (wasMapped)
294 W_MapView(view);
299 void
300 W_MapView(W_View *view)
302 if (!view->flags.mapped) {
303 if (view->flags.realized) {
304 XMapRaised(view->screen->display, view->window);
305 XFlush(view->screen->display);
306 view->flags.mapped = 1;
307 } else {
308 view->flags.mapWhenRealized = 1;
315 * W_MapSubviews-
316 * maps all children of the current view that where already realized.
318 void
319 W_MapSubviews(W_View *view)
321 XMapSubwindows(view->screen->display, view->window);
322 XFlush(view->screen->display);
324 view = view->childrenList;
325 while (view) {
326 view->flags.mapped = 1;
327 view->flags.mapWhenRealized = 0;
328 view = view->nextSister;
334 void
335 W_UnmapSubviews(W_View *view)
337 XUnmapSubwindows(view->screen->display, view->window);
338 XFlush(view->screen->display);
340 view = view->childrenList;
341 while (view) {
342 view->flags.mapped = 0;
343 view->flags.mapWhenRealized = 0;
344 view = view->nextSister;
350 void
351 W_UnmapView(W_View *view)
353 view->flags.mapWhenRealized = 0;
354 if (!view->flags.mapped)
355 return;
357 XUnmapWindow(view->screen->display, view->window);
358 XFlush(view->screen->display);
360 view->flags.mapped = 0;
364 W_View*
365 W_TopLevelOfView(W_View *view)
367 W_View *toplevel;
369 for (toplevel=view; !toplevel->flags.topLevel; toplevel=toplevel->parent);
371 return toplevel;
375 static void
376 destroyView(W_View *view)
378 W_View *ptr;
380 if (view->flags.alreadyDead)
381 return;
382 view->flags.alreadyDead = 1;
384 /* Do not leave focus in a inexisting control */
385 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view))==view)
386 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
388 if (view->flags.topLevel) {
389 W_FocusInfo *info = view->screen->focusInfo;
390 /* remove focus information associated to this toplevel */
392 if (info) {
393 if (info->toplevel==view) {
394 view->screen->focusInfo = info->next;
395 free(info);
396 } else {
397 while (info->next) {
398 if (info->next->toplevel == view)
399 break;
400 info = info->next;
402 if (info->next) {
403 W_FocusInfo *next = info->next->next;
404 free(info->next);
405 info->next = next;
407 /* else the toplevel did not have any focused subview */
412 /* destroy children recursively */
413 while (view->childrenList!=NULL) {
414 ptr = view->childrenList;
415 ptr->flags.parentDying = 1;
417 W_DestroyView(ptr);
419 if (ptr == view->childrenList) {
420 view->childrenList = ptr->nextSister;
421 ptr->parent = NULL;
425 W_CallDestroyHandlers(view);
427 if (view->flags.realized) {
428 XDeleteContext(view->screen->display, view->window, ViewContext);
430 /* if parent is being destroyed, it will die naturaly */
431 if (!view->flags.parentDying || view->flags.topLevel)
432 XDestroyWindow(view->screen->display, view->window);
435 /* remove self from parent's children list */
436 unparentView(view);
438 W_CleanUpEvents(view);
439 #if 0
440 if (view->dragSourceProcs)
441 free(view->dragSourceProcs);
443 if (view->dragDestinationProcs)
444 free(view->dragDestinationProcs);
445 #endif
446 free(view);
451 void
452 W_DestroyView(W_View *view)
454 W_ReleaseView(view);
459 void
460 W_MoveView(W_View *view, int x, int y)
462 assert(view->flags.root==0);
464 if (view->pos.x == x && view->pos.y == y)
465 return;
467 if (view->flags.realized) {
468 XMoveWindow(view->screen->display, view->window, x, y);
470 view->pos.x = x;
471 view->pos.y = y;
475 void
476 W_ResizeView(W_View *view, unsigned int width, unsigned int height)
478 int shrinked;
480 assert(width > 0);
481 assert(height > 0);
483 if (view->size.width == width && view->size.height == height)
484 return;
486 shrinked = width < view->size.width || height < view->size.height;
488 if (view->flags.realized) {
489 XResizeWindow(view->screen->display, view->window, width, height);
491 view->size.width = width;
492 view->size.height = height;
494 if (view->flags.notifySizeChanged)
495 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
499 void
500 W_RedisplayView(W_View *view)
502 XExposeEvent ev;
504 if (!view->flags.mapped)
505 return;
507 ev.type = Expose;
508 ev.display = view->screen->display;
509 ev.window = view->window;
510 ev.count = 0;
512 WMHandleEvent((XEvent*)&ev);
516 void
517 W_SetViewBackgroundColor(W_View *view, WMColor *color)
519 view->attribFlags |= CWBackPixel;
520 view->attribs.background_pixel = color->color.pixel;
521 if (view->flags.realized) {
522 XSetWindowBackground(view->screen->display, view->window,
523 color->color.pixel);
524 XClearWindow(view->screen->display, view->window);
530 W_View*
531 W_FocusedViewOfToplevel(W_View *view)
533 WMScreen *scr = view->screen;
534 W_FocusInfo *info;
536 for (info = scr->focusInfo; info!=NULL; info = info->next)
537 if (view == info->toplevel)
538 break;
540 if (!info)
541 return NULL;
543 return info->focused;
547 void
548 W_SetFocusOfTopLevel(W_View *toplevel, W_View *view)
550 WMScreen *scr = toplevel->screen;
551 XEvent event;
552 W_FocusInfo *info;
554 for (info = scr->focusInfo; info!=NULL; info = info->next)
555 if (toplevel == info->toplevel)
556 break;
558 if (!info) {
559 info = wmalloc(sizeof(W_FocusInfo));
560 info->toplevel = toplevel;
561 info->focused = view;
562 info->next = scr->focusInfo;
563 scr->focusInfo = info;
564 } else {
565 event.xfocus.mode = NotifyNormal;
566 event.xfocus.detail = NotifyDetailNone;
567 if (info->focused) {
568 /* simulate FocusOut event */
569 event.xfocus.type = FocusOut;
570 W_DispatchMessage(info->focused, &event);
572 info->focused = view;
574 if (view) {
575 /* simulate FocusIn event */
576 event.xfocus.type = FocusIn;
577 W_DispatchMessage(view, &event);
582 void
583 W_BroadcastMessage(W_View *targetParent, XEvent *event)
585 W_View *target;
587 target = targetParent->childrenList;
588 while (target!=NULL) {
589 W_DispatchMessage(target, event);
591 target = target->nextSister;
596 void
597 W_DispatchMessage(W_View *target, XEvent *event)
599 if (target->window==None)
600 return;
601 event->xclient.window = target->window;
602 event->xclient.display = target->screen->display;
604 WMHandleEvent(event);
606 XSendEvent(target->screen->display, target->window, False,
607 SubstructureNotifyMask, event);
613 WMView*
614 W_RetainView(WMView *view)
616 view->refCount++;
617 return view;
622 void
623 W_ReleaseView(WMView *view)
625 view->refCount--;
626 if (view->refCount < 1) {
627 destroyView(view);
632 WMWidget*
633 WMWidgetOfView(WMView *view)
635 return view->self;
639 WMSize
640 WMGetViewSize(WMView *view)
642 return view->size;
645 WMPoint
646 WMGetViewPosition(WMView *view)
648 return view->pos;
652 void
653 WMSetViewNotifySizeChanges(WMView *view, Bool flag)
655 view->flags.notifySizeChanged = flag;
658 Window
659 WMViewXID(WMView *view)
661 return view->window;