Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wview.c
1
2 #include "WINGsP.h"
3
4 #include <X11/Xresource.h>
5
6 /* the notifications about views */
7
8 char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
9 char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
10 char *WMViewRealizedNotification = "WMViewRealizedNotification";
11
12 #define EVENT_MASK  \
13     KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
14     EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
15     VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
16     SubstructureNotifyMask|SubstructureRedirectMask
17
18 static 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 */
34 };
35
36 static XContext ViewContext = 0;        /* context for views */
37
38 W_View *W_GetViewForXWindow(Display * display, Window window)
39 {
40         W_View *view;
41
42         if (XFindContext(display, window, ViewContext, (XPointer *) & view) == 0) {
43                 return view;
44         }
45         return NULL;
46 }
47
48 static void unparentView(W_View * view)
49 {
50         /* remove from parent's children list */
51         if (view->parent != NULL) {
52                 W_View *ptr;
53
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;
62                                 }
63                                 ptr = ptr->nextSister;
64                         }
65                 }
66         }
67         view->parent = NULL;
68 }
69
70 static void adoptChildView(W_View * view, W_View * child)
71 {
72         child->nextSister = NULL;
73
74         /* add to end of children list of parent */
75         if (view->childrenList == NULL) {
76                 view->childrenList = child;
77         } else {
78                 W_View *ptr;
79
80                 ptr = view->childrenList;
81                 while (ptr->nextSister != NULL)
82                         ptr = ptr->nextSister;
83                 ptr->nextSister = child;
84         }
85         child->parent = view;
86 }
87
88 static W_View *createView(W_Screen * screen, W_View * parent)
89 {
90         W_View *view;
91
92         if (ViewContext == 0)
93                 ViewContext = XUniqueContext();
94
95         view = wmalloc(sizeof(W_View));
96         memset(view, 0, sizeof(W_View));
97
98         view->screen = screen;
99
100         if (parent != NULL) {
101                 /* attributes are not valid for root window */
102                 view->attribFlags = CWEventMask | CWBitGravity;
103                 view->attribs = defAtts;
104
105                 view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel;
106                 view->attribs.background_pixel = W_PIXEL(screen->gray);
107                 view->attribs.border_pixel = W_PIXEL(screen->black);
108                 view->attribs.colormap = screen->colormap;
109
110                 view->backColor = WMRetainColor(screen->gray);
111
112                 adoptChildView(parent, view);
113         }
114
115         view->xic = 0;
116
117         view->refCount = 1;
118
119         view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
120
121         return view;
122 }
123
124 W_View *W_CreateView(W_View * parent)
125 {
126         return createView(parent->screen, parent);
127 }
128
129 W_View *W_CreateRootView(W_Screen * screen)
130 {
131         W_View *view;
132
133         view = createView(screen, NULL);
134
135         view->window = screen->rootWin;
136
137         view->flags.realized = 1;
138         view->flags.mapped = 1;
139         view->flags.root = 1;
140
141         view->size.width = WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
142         view->size.height = HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
143
144         return view;
145 }
146
147 W_View *W_CreateTopView(W_Screen * screen)
148 {
149         W_View *view;
150
151         view = createView(screen, screen->rootView);
152         if (!view)
153                 return NULL;
154
155         view->flags.topLevel = 1;
156         view->attribs.event_mask |= StructureNotifyMask;
157
158         return view;
159 }
160
161 W_View *W_CreateUnmanagedTopView(W_Screen * screen)
162 {
163         W_View *view;
164
165         view = createView(screen, screen->rootView);
166         if (!view)
167                 return NULL;
168
169         view->flags.topLevel = 1;
170         view->attribs.event_mask |= StructureNotifyMask;
171
172         view->attribFlags |= CWOverrideRedirect;
173         view->attribs.override_redirect = True;
174
175         return view;
176 }
177
178 void W_RealizeView(W_View * view)
179 {
180         Window parentWID;
181         Display *dpy = view->screen->display;
182         W_View *ptr;
183
184         assert(view->size.width > 0);
185         assert(view->size.height > 0);
186
187         if (view->parent && !view->parent->flags.realized) {
188                 wwarning("trying to realize widget of unrealized parent");
189                 return;
190         }
191
192         if (!view->flags.realized) {
193                 parentWID = view->parent->window;
194                 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
195                                              view->size.width, view->size.height, 0,
196                                              view->screen->depth, InputOutput,
197                                              view->screen->visual, view->attribFlags, &view->attribs);
198
199                 XSaveContext(dpy, view->window, ViewContext, (XPointer) view);
200
201                 view->flags.realized = 1;
202
203                 if (view->flags.mapWhenRealized) {
204                         W_MapView(view);
205                         view->flags.mapWhenRealized = 0;
206                 }
207
208                 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
209         }
210
211         /* realize children */
212         ptr = view->childrenList;
213         while (ptr != NULL) {
214                 W_RealizeView(ptr);
215
216                 ptr = ptr->nextSister;
217         }
218 }
219
220 void W_ReparentView(W_View * view, W_View * newParent, int x, int y)
221 {
222         Display *dpy = view->screen->display;
223
224         assert(!view->flags.topLevel);
225
226         unparentView(view);
227         adoptChildView(newParent, view);
228
229         if (view->flags.realized) {
230                 if (newParent->flags.realized) {
231                         XReparentWindow(dpy, view->window, newParent->window, x, y);
232                 } else {
233                         wwarning("trying to reparent realized view to unrealized parent");
234                         return;
235                 }
236         }
237
238         view->pos.x = x;
239         view->pos.y = y;
240 }
241
242 void W_RaiseView(W_View * view)
243 {
244         if (W_VIEW_REALIZED(view))
245                 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
246 }
247
248 void W_LowerView(W_View * view)
249 {
250         if (W_VIEW_REALIZED(view))
251                 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
252 }
253
254 void W_MapView(W_View * view)
255 {
256         if (!view->flags.mapped) {
257                 if (view->flags.realized) {
258                         XMapRaised(view->screen->display, view->window);
259                         XFlush(view->screen->display);
260                         view->flags.mapped = 1;
261                 } else {
262                         view->flags.mapWhenRealized = 1;
263                 }
264         }
265 }
266
267 /*
268  * W_MapSubviews-
269  *     maps all children of the current view that where already realized.
270  */
271 void W_MapSubviews(W_View * view)
272 {
273         XMapSubwindows(view->screen->display, view->window);
274         XFlush(view->screen->display);
275
276         view = view->childrenList;
277         while (view) {
278                 view->flags.mapped = 1;
279                 view->flags.mapWhenRealized = 0;
280                 view = view->nextSister;
281         }
282 }
283
284 void W_UnmapSubviews(W_View * view)
285 {
286         XUnmapSubwindows(view->screen->display, view->window);
287         XFlush(view->screen->display);
288
289         view = view->childrenList;
290         while (view) {
291                 view->flags.mapped = 0;
292                 view->flags.mapWhenRealized = 0;
293                 view = view->nextSister;
294         }
295 }
296
297 void W_UnmapView(W_View * view)
298 {
299         view->flags.mapWhenRealized = 0;
300         if (!view->flags.mapped)
301                 return;
302
303         XUnmapWindow(view->screen->display, view->window);
304         XFlush(view->screen->display);
305
306         view->flags.mapped = 0;
307 }
308
309 W_View *W_TopLevelOfView(W_View * view)
310 {
311         W_View *toplevel;
312
313         for (toplevel = view; toplevel && !toplevel->flags.topLevel; toplevel = toplevel->parent) ;
314
315         return toplevel;
316 }
317
318 static void destroyView(W_View * view)
319 {
320         W_View *ptr;
321
322         if (view->flags.alreadyDead)
323                 return;
324         view->flags.alreadyDead = 1;
325
326         /* delete the balloon text for the view, if there's any */
327         WMSetBalloonTextForView(NULL, view);
328
329         if (view->nextFocusChain)
330                 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
331         if (view->prevFocusChain)
332                 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
333
334         /* Do not leave focus in a inexisting control */
335         if (W_FocusedViewOfToplevel(W_TopLevelOfView(view)) == view)
336                 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
337
338         if (view->flags.topLevel) {
339                 W_FocusInfo *info = view->screen->focusInfo;
340                 /* remove focus information associated to this toplevel */
341
342                 if (info) {
343                         if (info->toplevel == view) {
344                                 view->screen->focusInfo = info->next;
345                                 wfree(info);
346                         } else {
347                                 while (info->next) {
348                                         if (info->next->toplevel == view)
349                                                 break;
350                                         info = info->next;
351                                 }
352                                 if (info->next) {
353                                         W_FocusInfo *next = info->next->next;
354                                         wfree(info->next);
355                                         info->next = next;
356                                 }
357                                 /* else the toplevel did not have any focused subview */
358                         }
359                 }
360         }
361
362         /* destroy children recursively */
363         while (view->childrenList != NULL) {
364                 ptr = view->childrenList;
365                 ptr->flags.parentDying = 1;
366
367                 W_DestroyView(ptr);
368
369                 if (ptr == view->childrenList) {
370                         view->childrenList = ptr->nextSister;
371                         ptr->parent = NULL;
372                 }
373         }
374
375         W_CallDestroyHandlers(view);
376
377         if (view->flags.realized) {
378                 XDeleteContext(view->screen->display, view->window, ViewContext);
379
380                 /* if parent is being destroyed, it will die naturaly */
381                 if (!view->flags.parentDying || view->flags.topLevel)
382                         XDestroyWindow(view->screen->display, view->window);
383         }
384
385         /* remove self from parent's children list */
386         unparentView(view);
387
388         /* the array has a wfree() destructor that will be called automatically */
389         WMFreeArray(view->eventHandlers);
390         view->eventHandlers = NULL;
391
392         WMRemoveNotificationObserver(view);
393
394         W_FreeViewXdndPart(view);
395
396         if (view->backColor)
397                 WMReleaseColor(view->backColor);
398
399         wfree(view);
400 }
401
402 void W_DestroyView(W_View * view)
403 {
404         view->refCount--;
405
406         if (view->refCount < 1) {
407                 destroyView(view);
408         }
409 }
410
411 void W_MoveView(W_View * view, int x, int y)
412 {
413         assert(view->flags.root == 0);
414
415         if (view->delegate && view->delegate->willMove) {
416                 (*view->delegate->willMove) (view->delegate, view, &x, &y);
417         }
418
419         if (view->pos.x == x && view->pos.y == y)
420                 return;
421
422         if (view->flags.realized) {
423                 XMoveWindow(view->screen->display, view->window, x, y);
424         }
425         view->pos.x = x;
426         view->pos.y = y;
427
428         if (view->delegate && view->delegate->didMove) {
429                 (*view->delegate->didMove) (view->delegate, view);
430         }
431 }
432
433 void W_ResizeView(W_View * view, unsigned int width, unsigned int height)
434 {
435         /*int shrinked; */
436
437         if (view->delegate && view->delegate->willResize) {
438                 (*view->delegate->willResize) (view->delegate, view, &width, &height);
439         }
440
441         assert(width > 0);
442         assert(height > 0);
443
444         if (view->size.width == width && view->size.height == height)
445                 return;
446
447         /*shrinked = width < view->size.width || height < view->size.height; */
448
449         if (view->flags.realized) {
450                 XResizeWindow(view->screen->display, view->window, width, height);
451         }
452         view->size.width = width;
453         view->size.height = height;
454
455         if (view->delegate && view->delegate->didResize) {
456                 (*view->delegate->didResize) (view->delegate, view);
457         }
458
459         /* // TODO. replace in WINGs code, with the didResize delegate */
460         if (view->flags.notifySizeChanged)
461                 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
462 }
463
464 void W_RedisplayView(W_View * view)
465 {
466         XEvent ev;
467
468         if (!view->flags.mapped)
469                 return;
470
471         ev.xexpose.type = Expose;
472         ev.xexpose.display = view->screen->display;
473         ev.xexpose.window = view->window;
474         ev.xexpose.count = 0;
475
476         ev.xexpose.serial = 0;
477
478         WMHandleEvent(&ev);
479 }
480
481 void W_SetViewBackgroundColor(W_View * view, WMColor * color)
482 {
483         if (view->backColor)
484                 WMReleaseColor(view->backColor);
485         view->backColor = WMRetainColor(color);
486
487         view->attribFlags |= CWBackPixel;
488         view->attribs.background_pixel = W_PIXEL(color);
489         if (view->flags.realized) {
490                 XSetWindowBackground(view->screen->display, view->window, W_PIXEL(color));
491                 XClearWindow(view->screen->display, view->window);
492         }
493 }
494
495 void W_SetViewCursor(W_View * view, Cursor cursor)
496 {
497         view->cursor = cursor;
498         if (W_VIEW_REALIZED(view)) {
499                 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
500         } else {
501                 view->attribFlags |= CWCursor;
502                 view->attribs.cursor = cursor;
503         }
504 }
505
506 W_View *W_FocusedViewOfToplevel(W_View * view)
507 {
508         WMScreen *scr = view->screen;
509         W_FocusInfo *info;
510
511         for (info = scr->focusInfo; info != NULL; info = info->next)
512                 if (view == info->toplevel)
513                         break;
514
515         if (!info)
516                 return NULL;
517
518         return info->focused;
519 }
520
521 void W_SetFocusOfTopLevel(W_View * toplevel, W_View * view)
522 {
523         WMScreen *scr = toplevel->screen;
524         XEvent event;
525         W_FocusInfo *info;
526
527         for (info = scr->focusInfo; info != NULL; info = info->next)
528                 if (toplevel == info->toplevel)
529                         break;
530
531         if (!info) {
532                 info = wmalloc(sizeof(W_FocusInfo));
533                 info->toplevel = toplevel;
534                 info->focused = view;
535                 info->next = scr->focusInfo;
536                 scr->focusInfo = info;
537         } else {
538                 event.xfocus.mode = NotifyNormal;
539                 event.xfocus.detail = NotifyDetailNone;
540                 if (info->focused) {
541                         /* simulate FocusOut event */
542                         event.xfocus.type = FocusOut;
543                         W_DispatchMessage(info->focused, &event);
544                 }
545                 info->focused = view;
546         }
547         if (view) {
548                 /* simulate FocusIn event */
549                 event.xfocus.type = FocusIn;
550                 W_DispatchMessage(view, &event);
551         }
552 }
553
554 void W_BroadcastMessage(W_View * targetParent, XEvent * event)
555 {
556         W_View *target;
557
558         target = targetParent->childrenList;
559         while (target != NULL) {
560                 W_DispatchMessage(target, event);
561
562                 target = target->nextSister;
563         }
564 }
565
566 void W_DispatchMessage(W_View * target, XEvent * event)
567 {
568         if (target->window == None)
569                 return;
570         event->xclient.window = target->window;
571         event->xclient.display = target->screen->display;
572
573         WMHandleEvent(event);
574         /*
575            XSendEvent(target->screen->display, target->window, False,
576            SubstructureNotifyMask, event);
577          */
578 }
579
580 WMView *W_RetainView(WMView * view)
581 {
582         view->refCount++;
583
584         return view;
585 }
586
587 void W_ReleaseView(WMView * view)
588 {
589         view->refCount--;
590
591         if (view->refCount < 1) {
592                 destroyView(view);
593         }
594 }
595
596 WMWidget *WMWidgetOfView(WMView * view)
597 {
598         return view->self;
599 }
600
601 WMSize WMGetViewSize(WMView * view)
602 {
603         return view->size;
604 }
605
606 WMPoint WMGetViewPosition(WMView * view)
607 {
608         return view->pos;
609 }
610
611 void WMSetViewNotifySizeChanges(WMView * view, Bool flag)
612 {
613         view->flags.notifySizeChanged = ((flag == 0) ? 0 : 1);
614 }
615
616 Window WMViewXID(WMView * view)
617 {
618         return view->window;
619 }
620
621 WMPoint WMGetViewScreenPosition(WMView * view)
622 {
623         WMScreen *scr = W_VIEW_SCREEN(view);
624         Window foo;
625         int x, y, topX, topY;
626         unsigned int bar;
627         WMView *topView;
628
629         topView = view;
630         while (topView->parent && topView->parent != scr->rootView)
631                 topView = topView->parent;
632
633         if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX, &topY, &bar, &bar, &bar, &bar)) {
634                 topX = topY = 0;
635         }
636
637         XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view), scr->rootWin, 0, 0, &x, &y, &foo);
638
639         return wmkpoint(x - topX, y - topY);
640 }
641
642 static void resizedParent(void *self, WMNotification * notif)
643 {
644         WMSize size = WMGetViewSize((WMView *) WMGetNotificationObject(notif));
645         WMView *view = (WMView *) self;
646
647         W_MoveView(view, view->leftOffs, view->topOffs);
648         W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
649                      size.height - (view->topOffs + view->bottomOffs));
650 }
651
652 void WMSetViewExpandsToParent(WMView * view, int leftOffs, int topOffs, int rightOffs, int bottomOffs)
653 {
654         WMSize size = view->parent->size;
655
656         view->topOffs = topOffs;
657         view->bottomOffs = bottomOffs;
658         view->leftOffs = leftOffs;
659         view->rightOffs = rightOffs;
660
661         WMAddNotificationObserver(resizedParent, view, WMViewSizeDidChangeNotification, view->parent);
662         WMSetViewNotifySizeChanges(view->parent, True);
663
664         W_MoveView(view, leftOffs, topOffs);
665         W_ResizeView(view, size.width - (leftOffs + rightOffs), size.height - (topOffs + bottomOffs));
666 }