src/misc.c: updated GetShortcutString
[wmaker-crm.git] / WINGs / wview.c
blob1138f36756fb969e1873bfbc9059ba48f46b85ba
2 #include "WINGsP.h"
4 #include <X11/Xresource.h>
6 /* the notifications about views */
8 char *WMViewSizeDidChangeNotification = "WMViewSizeDidChangeNotification";
9 char *WMViewFocusDidChangeNotification = "WMViewFocusDidChangeNotification";
10 char *WMViewRealizedNotification = "WMViewRealizedNotification";
12 #define EVENT_MASK \
13 KeyPressMask|KeyReleaseMask|ButtonPressMask|ButtonReleaseMask| \
14 EnterWindowMask|LeaveWindowMask|PointerMotionMask|ExposureMask| \
15 VisibilityChangeMask|FocusChangeMask|PropertyChangeMask|\
16 SubstructureNotifyMask|SubstructureRedirectMask
18 static const 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 */
36 static XContext ViewContext = 0; /* context for views */
38 W_View *W_GetViewForXWindow(Display * display, Window window)
40 W_View *view;
42 if (XFindContext(display, window, ViewContext, (XPointer *) & view) == 0) {
43 return view;
45 return NULL;
48 static void unparentView(W_View * view)
50 /* remove from parent's children list */
51 if (view->parent != NULL) {
52 W_View *ptr;
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;
63 ptr = ptr->nextSister;
67 view->parent = NULL;
70 static void adoptChildView(W_View * view, W_View * child)
72 child->nextSister = NULL;
74 /* add to end of children list of parent */
75 if (view->childrenList == NULL) {
76 view->childrenList = child;
77 } else {
78 W_View *ptr;
80 ptr = view->childrenList;
81 while (ptr->nextSister != NULL)
82 ptr = ptr->nextSister;
83 ptr->nextSister = child;
85 child->parent = view;
88 static W_View *createView(W_Screen * screen, W_View * parent)
90 W_View *view;
92 if (ViewContext == 0)
93 ViewContext = XUniqueContext();
95 view = wmalloc(sizeof(W_View));
96 view->screen = screen;
98 if (parent != NULL) {
99 /* attributes are not valid for root window */
100 view->attribFlags = CWEventMask | CWBitGravity;
101 view->attribs = defAtts;
103 view->attribFlags |= CWBackPixel | CWColormap | CWBorderPixel;
104 view->attribs.background_pixel = W_PIXEL(screen->gray);
105 view->attribs.border_pixel = W_PIXEL(screen->black);
106 view->attribs.colormap = screen->colormap;
108 view->backColor = WMRetainColor(screen->gray);
110 adoptChildView(parent, view);
113 view->xic = 0;
115 view->refCount = 1;
117 view->eventHandlers = WMCreateArrayWithDestructor(4, wfree);
119 return view;
122 W_View *W_CreateView(W_View * parent)
124 return createView(parent->screen, parent);
127 W_View *W_CreateRootView(W_Screen * screen)
129 W_View *view;
131 view = createView(screen, NULL);
133 view->window = screen->rootWin;
135 view->flags.realized = 1;
136 view->flags.mapped = 1;
137 view->flags.root = 1;
139 view->size.width = WidthOfScreen(ScreenOfDisplay(screen->display, screen->screen));
140 view->size.height = HeightOfScreen(ScreenOfDisplay(screen->display, screen->screen));
142 return view;
145 W_View *W_CreateTopView(W_Screen * screen)
147 W_View *view;
149 view = createView(screen, screen->rootView);
150 if (!view)
151 return NULL;
153 view->flags.topLevel = 1;
154 view->attribs.event_mask |= StructureNotifyMask;
156 return view;
159 W_View *W_CreateUnmanagedTopView(W_Screen * screen)
161 W_View *view;
163 view = createView(screen, screen->rootView);
164 if (!view)
165 return NULL;
167 view->flags.topLevel = 1;
168 view->attribs.event_mask |= StructureNotifyMask;
170 view->attribFlags |= CWOverrideRedirect;
171 view->attribs.override_redirect = True;
173 return view;
176 void W_RealizeView(W_View * view)
178 Window parentWID;
179 Display *dpy = view->screen->display;
180 W_View *ptr;
182 assert(view->size.width > 0);
183 assert(view->size.height > 0);
185 if (view->parent && !view->parent->flags.realized) {
186 wwarning("trying to realize widget of unrealized parent");
187 return;
190 if (!view->flags.realized) {
191 parentWID = view->parent->window;
192 view->window = XCreateWindow(dpy, parentWID, view->pos.x, view->pos.y,
193 view->size.width, view->size.height, 0,
194 view->screen->depth, InputOutput,
195 view->screen->visual, view->attribFlags, &view->attribs);
197 XSaveContext(dpy, view->window, ViewContext, (XPointer) view);
199 view->flags.realized = 1;
201 if (view->flags.mapWhenRealized) {
202 W_MapView(view);
203 view->flags.mapWhenRealized = 0;
206 WMPostNotificationName(WMViewRealizedNotification, view, NULL);
209 /* realize children */
210 ptr = view->childrenList;
211 while (ptr != NULL) {
212 W_RealizeView(ptr);
214 ptr = ptr->nextSister;
218 void W_ReparentView(W_View * view, W_View * newParent, int x, int y)
220 Display *dpy = view->screen->display;
222 assert(!view->flags.topLevel);
224 unparentView(view);
225 adoptChildView(newParent, view);
227 if (view->flags.realized) {
228 if (newParent->flags.realized) {
229 XReparentWindow(dpy, view->window, newParent->window, x, y);
230 } else {
231 wwarning("trying to reparent realized view to unrealized parent");
232 return;
236 view->pos.x = x;
237 view->pos.y = y;
240 void W_RaiseView(W_View * view)
242 if (W_VIEW_REALIZED(view))
243 XRaiseWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
246 void W_LowerView(W_View * view)
248 if (W_VIEW_REALIZED(view))
249 XLowerWindow(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view));
252 void W_MapView(W_View * view)
254 if (!view->flags.mapped) {
255 if (view->flags.realized) {
256 XMapRaised(view->screen->display, view->window);
257 XFlush(view->screen->display);
258 view->flags.mapped = 1;
259 } else {
260 view->flags.mapWhenRealized = 1;
266 * W_MapSubviews-
267 * maps all children of the current view that where already realized.
269 void W_MapSubviews(W_View * view)
271 XMapSubwindows(view->screen->display, view->window);
272 XFlush(view->screen->display);
274 view = view->childrenList;
275 while (view) {
276 view->flags.mapped = 1;
277 view->flags.mapWhenRealized = 0;
278 view = view->nextSister;
282 void W_UnmapSubviews(W_View * view)
284 XUnmapSubwindows(view->screen->display, view->window);
285 XFlush(view->screen->display);
287 view = view->childrenList;
288 while (view) {
289 view->flags.mapped = 0;
290 view->flags.mapWhenRealized = 0;
291 view = view->nextSister;
295 void W_UnmapView(W_View * view)
297 view->flags.mapWhenRealized = 0;
298 if (!view->flags.mapped)
299 return;
301 XUnmapWindow(view->screen->display, view->window);
302 XFlush(view->screen->display);
304 view->flags.mapped = 0;
307 W_View *W_TopLevelOfView(W_View * view)
309 W_View *toplevel;
311 for (toplevel = view; toplevel && !toplevel->flags.topLevel; toplevel = toplevel->parent) ;
313 return toplevel;
316 static void destroyView(W_View * view)
318 W_View *ptr;
320 if (view->flags.alreadyDead)
321 return;
322 view->flags.alreadyDead = 1;
324 /* delete the balloon text for the view, if there's any */
325 WMSetBalloonTextForView(NULL, view);
327 if (view->nextFocusChain)
328 view->nextFocusChain->prevFocusChain = view->prevFocusChain;
329 if (view->prevFocusChain)
330 view->prevFocusChain->nextFocusChain = view->nextFocusChain;
332 /* Do not leave focus in a inexisting control */
333 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view)) == view)
334 W_SetFocusOfTopLevel(W_TopLevelOfView(view), NULL);
336 if (view->flags.topLevel) {
337 W_FocusInfo *info = view->screen->focusInfo;
338 /* remove focus information associated to this toplevel */
340 if (info) {
341 if (info->toplevel == view) {
342 view->screen->focusInfo = info->next;
343 wfree(info);
344 } else {
345 while (info->next) {
346 if (info->next->toplevel == view)
347 break;
348 info = info->next;
350 if (info->next) {
351 W_FocusInfo *next = info->next->next;
352 wfree(info->next);
353 info->next = next;
355 /* else the toplevel did not have any focused subview */
360 /* destroy children recursively */
361 while (view->childrenList != NULL) {
362 ptr = view->childrenList;
363 ptr->flags.parentDying = 1;
365 W_DestroyView(ptr);
367 if (ptr == view->childrenList) {
368 view->childrenList = ptr->nextSister;
369 ptr->parent = NULL;
373 W_CallDestroyHandlers(view);
375 if (view->flags.realized) {
376 XDeleteContext(view->screen->display, view->window, ViewContext);
378 /* if parent is being destroyed, it will die naturaly */
379 if (!view->flags.parentDying || view->flags.topLevel)
380 XDestroyWindow(view->screen->display, view->window);
383 /* remove self from parent's children list */
384 unparentView(view);
386 /* the array has a wfree() destructor that will be called automatically */
387 WMFreeArray(view->eventHandlers);
388 view->eventHandlers = NULL;
390 WMRemoveNotificationObserver(view);
392 W_FreeViewXdndPart(view);
394 if (view->backColor)
395 WMReleaseColor(view->backColor);
397 wfree(view);
400 void W_DestroyView(W_View * view)
402 view->refCount--;
404 if (view->refCount < 1) {
405 destroyView(view);
409 void W_MoveView(W_View * view, int x, int y)
411 assert(view->flags.root == 0);
413 if (view->delegate && view->delegate->willMove) {
414 (*view->delegate->willMove) (view->delegate, view, &x, &y);
417 if (view->pos.x == x && view->pos.y == y)
418 return;
420 if (view->flags.realized) {
421 XMoveWindow(view->screen->display, view->window, x, y);
423 view->pos.x = x;
424 view->pos.y = y;
426 if (view->delegate && view->delegate->didMove) {
427 (*view->delegate->didMove) (view->delegate, view);
431 void W_ResizeView(W_View * view, unsigned int width, unsigned int height)
433 /*int shrinked; */
435 if (view->delegate && view->delegate->willResize) {
436 (*view->delegate->willResize) (view->delegate, view, &width, &height);
439 assert(width > 0);
440 assert(height > 0);
442 if (view->size.width == width && view->size.height == height)
443 return;
445 /*shrinked = width < view->size.width || height < view->size.height; */
447 if (view->flags.realized) {
448 XResizeWindow(view->screen->display, view->window, width, height);
450 view->size.width = width;
451 view->size.height = height;
453 if (view->delegate && view->delegate->didResize) {
454 (*view->delegate->didResize) (view->delegate, view);
457 /* // TODO. replace in WINGs code, with the didResize delegate */
458 if (view->flags.notifySizeChanged)
459 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
462 void W_RedisplayView(W_View * view)
464 XEvent ev;
466 if (!view->flags.mapped)
467 return;
469 ev.xexpose.type = Expose;
470 ev.xexpose.display = view->screen->display;
471 ev.xexpose.window = view->window;
472 ev.xexpose.count = 0;
474 ev.xexpose.serial = 0;
476 WMHandleEvent(&ev);
479 void W_SetViewBackgroundColor(W_View * view, WMColor * color)
481 if (view->backColor)
482 WMReleaseColor(view->backColor);
483 view->backColor = WMRetainColor(color);
485 view->attribFlags |= CWBackPixel;
486 view->attribs.background_pixel = W_PIXEL(color);
487 if (view->flags.realized) {
488 XSetWindowBackground(view->screen->display, view->window, W_PIXEL(color));
489 XClearWindow(view->screen->display, view->window);
493 void W_SetViewCursor(W_View * view, Cursor cursor)
495 view->cursor = cursor;
496 if (W_VIEW_REALIZED(view)) {
497 XDefineCursor(W_VIEW_DISPLAY(view), W_VIEW_DRAWABLE(view), cursor);
498 } else {
499 view->attribFlags |= CWCursor;
500 view->attribs.cursor = cursor;
504 W_View *W_FocusedViewOfToplevel(W_View * view)
506 WMScreen *scr = view->screen;
507 W_FocusInfo *info;
509 for (info = scr->focusInfo; info != NULL; info = info->next)
510 if (view == info->toplevel)
511 break;
513 if (!info)
514 return NULL;
516 return info->focused;
519 void W_SetFocusOfTopLevel(W_View * toplevel, W_View * view)
521 WMScreen *scr = toplevel->screen;
522 XEvent event;
523 W_FocusInfo *info;
525 for (info = scr->focusInfo; info != NULL; info = info->next)
526 if (toplevel == info->toplevel)
527 break;
529 if (!info) {
530 info = wmalloc(sizeof(W_FocusInfo));
531 info->toplevel = toplevel;
532 info->focused = view;
533 info->next = scr->focusInfo;
534 scr->focusInfo = info;
535 } else {
536 event.xfocus.mode = NotifyNormal;
537 event.xfocus.detail = NotifyDetailNone;
538 if (info->focused) {
539 /* simulate FocusOut event */
540 event.xfocus.type = FocusOut;
541 W_DispatchMessage(info->focused, &event);
543 info->focused = view;
545 if (view) {
546 /* simulate FocusIn event */
547 event.xfocus.type = FocusIn;
548 W_DispatchMessage(view, &event);
552 void W_BroadcastMessage(W_View * targetParent, XEvent * event)
554 W_View *target;
556 target = targetParent->childrenList;
557 while (target != NULL) {
558 W_DispatchMessage(target, event);
560 target = target->nextSister;
564 void W_DispatchMessage(W_View * target, XEvent * event)
566 if (target->window == None)
567 return;
568 event->xclient.window = target->window;
569 event->xclient.display = target->screen->display;
571 WMHandleEvent(event);
573 XSendEvent(target->screen->display, target->window, False,
574 SubstructureNotifyMask, event);
578 WMView *W_RetainView(WMView * view)
580 view->refCount++;
582 return view;
585 void W_ReleaseView(WMView * view)
587 view->refCount--;
589 if (view->refCount < 1) {
590 destroyView(view);
594 WMWidget *WMWidgetOfView(WMView * view)
596 return view->self;
599 WMSize WMGetViewSize(WMView * view)
601 return view->size;
604 WMPoint WMGetViewPosition(WMView * view)
606 return view->pos;
609 void WMSetViewNotifySizeChanges(WMView * view, Bool flag)
611 view->flags.notifySizeChanged = ((flag == 0) ? 0 : 1);
614 Window WMViewXID(WMView * view)
616 return view->window;
619 WMPoint WMGetViewScreenPosition(WMView * view)
621 WMScreen *scr = W_VIEW_SCREEN(view);
622 Window foo;
623 int x, y, topX, topY;
624 unsigned int bar;
625 WMView *topView;
627 topView = view;
628 while (topView->parent && topView->parent != scr->rootView)
629 topView = topView->parent;
631 if (!XGetGeometry(scr->display, W_VIEW_DRAWABLE(topView), &foo, &topX, &topY, &bar, &bar, &bar, &bar)) {
632 topX = topY = 0;
635 XTranslateCoordinates(scr->display, W_VIEW_DRAWABLE(view), scr->rootWin, 0, 0, &x, &y, &foo);
637 return wmkpoint(x - topX, y - topY);
640 static void resizedParent(void *self, WMNotification * notif)
642 WMSize size = WMGetViewSize((WMView *) WMGetNotificationObject(notif));
643 WMView *view = (WMView *) self;
645 W_MoveView(view, view->leftOffs, view->topOffs);
646 W_ResizeView(view, size.width - (view->leftOffs + view->rightOffs),
647 size.height - (view->topOffs + view->bottomOffs));
650 void WMSetViewExpandsToParent(WMView * view, int leftOffs, int topOffs, int rightOffs, int bottomOffs)
652 WMSize size = view->parent->size;
654 view->topOffs = topOffs;
655 view->bottomOffs = bottomOffs;
656 view->leftOffs = leftOffs;
657 view->rightOffs = rightOffs;
659 WMAddNotificationObserver(resizedParent, view, WMViewSizeDidChangeNotification, view->parent);
660 WMSetViewNotifySizeChanges(view->parent, True);
662 W_MoveView(view, leftOffs, topOffs);
663 W_ResizeView(view, size.width - (leftOffs + rightOffs), size.height - (topOffs + bottomOffs));