4 #include <X11/Xresource.h>
6 /* the notifications about views */
8 char *WMViewSizeDidChangeNotification
= "WMViewSizeDidChangeNotification";
9 char *WMViewFocusDidChangeNotification
= "WMViewFocusDidChangeNotification";
10 char *WMViewRealizedNotification
= "WMViewRealizedNotification";
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 */
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 */
36 static XContext ViewContext
= 0; /* context for views */
38 W_View
*W_GetViewForXWindow(Display
* display
, Window window
)
42 if (XFindContext(display
, window
, ViewContext
, (XPointer
*) & view
) == 0) {
48 static void unparentView(W_View
* view
)
50 /* remove from parent's children list */
51 if (view
->parent
!= NULL
) {
54 ptr
= view
->parent
->childrenList
;
56 view
->parent
->childrenList
= view
->nextSister
;
59 if (ptr
->nextSister
== view
) {
60 ptr
->nextSister
= view
->nextSister
;
63 ptr
= ptr
->nextSister
;
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
;
80 ptr
= view
->childrenList
;
81 while (ptr
->nextSister
!= NULL
)
82 ptr
= ptr
->nextSister
;
83 ptr
->nextSister
= child
;
88 static W_View
*createView(W_Screen
* screen
, W_View
* parent
)
93 ViewContext
= XUniqueContext();
95 view
= wmalloc(sizeof(W_View
));
96 view
->screen
= screen
;
99 /* attributes are not valid for root window */
100 view
->attribFlags
= CWEventMask
| CWBitGravity
;
101 view
->attribs
= defAtts
;
103 view
->attribFlags
|= CWBackPixel
| CWColormap
| CWBorderPixel
| CWBackPixmap
;
104 view
->attribs
.background_pixmap
= None
;
105 view
->attribs
.background_pixel
= W_PIXEL(screen
->gray
);
106 view
->attribs
.border_pixel
= W_PIXEL(screen
->black
);
107 view
->attribs
.colormap
= screen
->colormap
;
109 view
->backColor
= WMRetainColor(screen
->gray
);
111 adoptChildView(parent
, view
);
118 view
->eventHandlers
= WMCreateArrayWithDestructor(4, wfree
);
123 W_View
*W_CreateView(W_View
* parent
)
125 return createView(parent
->screen
, parent
);
128 W_View
*W_CreateRootView(W_Screen
* screen
)
132 view
= createView(screen
, NULL
);
134 view
->window
= screen
->rootWin
;
136 view
->flags
.realized
= 1;
137 view
->flags
.mapped
= 1;
138 view
->flags
.root
= 1;
140 view
->size
.width
= WidthOfScreen(ScreenOfDisplay(screen
->display
, screen
->screen
));
141 view
->size
.height
= HeightOfScreen(ScreenOfDisplay(screen
->display
, screen
->screen
));
146 W_View
*W_CreateTopView(W_Screen
* screen
)
150 view
= createView(screen
, screen
->rootView
);
154 view
->flags
.topLevel
= 1;
155 view
->attribs
.event_mask
|= StructureNotifyMask
;
160 W_View
*W_CreateUnmanagedTopView(W_Screen
* screen
)
164 view
= createView(screen
, screen
->rootView
);
168 view
->flags
.topLevel
= 1;
169 view
->attribs
.event_mask
|= StructureNotifyMask
;
171 view
->attribFlags
|= CWOverrideRedirect
;
172 view
->attribs
.override_redirect
= True
;
177 void W_RealizeView(W_View
* view
)
180 Display
*dpy
= view
->screen
->display
;
183 assert(view
->size
.width
> 0);
184 assert(view
->size
.height
> 0);
186 if (view
->parent
&& !view
->parent
->flags
.realized
) {
187 wwarning("trying to realize widget of unrealized parent");
191 if (!view
->flags
.realized
) {
193 if (view
->parent
== NULL
) {
194 wwarning("trying to realize widget without parent");
198 parentWID
= view
->parent
->window
;
199 view
->window
= XCreateWindow(dpy
, parentWID
, view
->pos
.x
, view
->pos
.y
,
200 view
->size
.width
, view
->size
.height
, 0,
201 view
->screen
->depth
, InputOutput
,
202 view
->screen
->visual
, view
->attribFlags
, &view
->attribs
);
204 XSaveContext(dpy
, view
->window
, ViewContext
, (XPointer
) view
);
206 view
->flags
.realized
= 1;
208 if (view
->flags
.mapWhenRealized
) {
210 view
->flags
.mapWhenRealized
= 0;
213 WMPostNotificationName(WMViewRealizedNotification
, view
, NULL
);
216 /* realize children */
217 ptr
= view
->childrenList
;
218 while (ptr
!= NULL
) {
221 ptr
= ptr
->nextSister
;
225 void W_ReparentView(W_View
* view
, W_View
* newParent
, int x
, int y
)
227 Display
*dpy
= view
->screen
->display
;
229 assert(!view
->flags
.topLevel
);
232 adoptChildView(newParent
, view
);
234 if (view
->flags
.realized
) {
235 if (newParent
->flags
.realized
) {
236 XReparentWindow(dpy
, view
->window
, newParent
->window
, x
, y
);
238 wwarning("trying to reparent realized view to unrealized parent");
247 void W_RaiseView(W_View
* view
)
249 if (W_VIEW_REALIZED(view
))
250 XRaiseWindow(W_VIEW_DISPLAY(view
), W_VIEW_DRAWABLE(view
));
253 void W_LowerView(W_View
* view
)
255 if (W_VIEW_REALIZED(view
))
256 XLowerWindow(W_VIEW_DISPLAY(view
), W_VIEW_DRAWABLE(view
));
259 void W_MapView(W_View
* view
)
261 if (!view
->flags
.mapped
) {
262 if (view
->flags
.realized
) {
263 XMapRaised(view
->screen
->display
, view
->window
);
264 XFlush(view
->screen
->display
);
265 view
->flags
.mapped
= 1;
267 view
->flags
.mapWhenRealized
= 1;
274 * maps all children of the current view that where already realized.
276 void W_MapSubviews(W_View
* view
)
278 XMapSubwindows(view
->screen
->display
, view
->window
);
279 XFlush(view
->screen
->display
);
281 view
= view
->childrenList
;
283 view
->flags
.mapped
= 1;
284 view
->flags
.mapWhenRealized
= 0;
285 view
= view
->nextSister
;
289 void W_UnmapSubviews(W_View
* view
)
291 XUnmapSubwindows(view
->screen
->display
, view
->window
);
292 XFlush(view
->screen
->display
);
294 view
= view
->childrenList
;
296 view
->flags
.mapped
= 0;
297 view
->flags
.mapWhenRealized
= 0;
298 view
= view
->nextSister
;
302 void W_UnmapView(W_View
* view
)
304 view
->flags
.mapWhenRealized
= 0;
305 if (!view
->flags
.mapped
)
308 XUnmapWindow(view
->screen
->display
, view
->window
);
309 XFlush(view
->screen
->display
);
311 view
->flags
.mapped
= 0;
314 W_View
*W_TopLevelOfView(W_View
* view
)
318 for (toplevel
= view
; toplevel
&& !toplevel
->flags
.topLevel
; toplevel
= toplevel
->parent
) ;
323 static void destroyView(W_View
* view
)
327 if (view
->flags
.alreadyDead
)
329 view
->flags
.alreadyDead
= 1;
331 /* delete the balloon text for the view, if there's any */
332 WMSetBalloonTextForView(NULL
, view
);
334 if (view
->nextFocusChain
)
335 view
->nextFocusChain
->prevFocusChain
= view
->prevFocusChain
;
336 if (view
->prevFocusChain
)
337 view
->prevFocusChain
->nextFocusChain
= view
->nextFocusChain
;
339 /* Do not leave focus in a inexisting control */
340 if (W_FocusedViewOfToplevel(W_TopLevelOfView(view
)) == view
)
341 W_SetFocusOfTopLevel(W_TopLevelOfView(view
), NULL
);
343 if (view
->flags
.topLevel
) {
344 W_FocusInfo
*info
= view
->screen
->focusInfo
;
345 /* remove focus information associated to this toplevel */
348 if (info
->toplevel
== view
) {
349 view
->screen
->focusInfo
= info
->next
;
353 if (info
->next
->toplevel
== view
)
358 W_FocusInfo
*next
= info
->next
->next
;
362 /* else the toplevel did not have any focused subview */
367 /* destroy children recursively */
368 while (view
->childrenList
!= NULL
) {
369 ptr
= view
->childrenList
;
370 ptr
->flags
.parentDying
= 1;
374 if (ptr
== view
->childrenList
) {
375 view
->childrenList
= ptr
->nextSister
;
380 W_CallDestroyHandlers(view
);
382 if (view
->flags
.realized
) {
383 XDeleteContext(view
->screen
->display
, view
->window
, ViewContext
);
385 /* if parent is being destroyed, it will die naturaly */
386 if (!view
->flags
.parentDying
|| view
->flags
.topLevel
)
387 XDestroyWindow(view
->screen
->display
, view
->window
);
390 /* remove self from parent's children list */
393 /* the array has a wfree() destructor that will be called automatically */
394 WMFreeArray(view
->eventHandlers
);
395 view
->eventHandlers
= NULL
;
397 WMRemoveNotificationObserver(view
);
399 W_FreeViewXdndPart(view
);
402 WMReleaseColor(view
->backColor
);
407 void W_DestroyView(W_View
* view
)
411 if (view
->refCount
< 1) {
416 void W_MoveView(W_View
* view
, int x
, int y
)
418 assert(view
->flags
.root
== 0);
420 if (view
->delegate
&& view
->delegate
->willMove
) {
421 (*view
->delegate
->willMove
) (view
->delegate
, view
, &x
, &y
);
424 if (view
->pos
.x
== x
&& view
->pos
.y
== y
)
427 if (view
->flags
.realized
) {
428 XMoveWindow(view
->screen
->display
, view
->window
, x
, y
);
433 if (view
->delegate
&& view
->delegate
->didMove
) {
434 (*view
->delegate
->didMove
) (view
->delegate
, view
);
438 void W_ResizeView(W_View
* view
, unsigned int width
, unsigned int height
)
442 if (view
->delegate
&& view
->delegate
->willResize
) {
443 (*view
->delegate
->willResize
) (view
->delegate
, view
, &width
, &height
);
449 if (view
->size
.width
== width
&& view
->size
.height
== height
)
452 /*shrinked = width < view->size.width || height < view->size.height; */
454 if (view
->flags
.realized
) {
455 XResizeWindow(view
->screen
->display
, view
->window
, width
, height
);
457 view
->size
.width
= width
;
458 view
->size
.height
= height
;
460 if (view
->delegate
&& view
->delegate
->didResize
) {
461 (*view
->delegate
->didResize
) (view
->delegate
, view
);
464 /* // TODO. replace in WINGs code, with the didResize delegate */
465 if (view
->flags
.notifySizeChanged
)
466 WMPostNotificationName(WMViewSizeDidChangeNotification
, view
, NULL
);
469 void W_RedisplayView(W_View
* view
)
473 if (!view
->flags
.mapped
)
476 ev
.xexpose
.type
= Expose
;
477 ev
.xexpose
.display
= view
->screen
->display
;
478 ev
.xexpose
.window
= view
->window
;
479 ev
.xexpose
.count
= 0;
481 ev
.xexpose
.serial
= 0;
486 void W_SetViewBackgroundColor(W_View
* view
, WMColor
* color
)
489 WMReleaseColor(view
->backColor
);
490 view
->backColor
= WMRetainColor(color
);
492 view
->attribFlags
|= CWBackPixel
;
493 view
->attribFlags
&= ~CWBackPixmap
;
494 view
->attribs
.background_pixel
= W_PIXEL(color
);
495 if (view
->flags
.realized
) {
496 XSetWindowBackground(view
->screen
->display
, view
->window
, W_PIXEL(color
));
497 XClearWindow(view
->screen
->display
, view
->window
);
501 void W_SetViewBackgroundPixmap(W_View
*view
, WMPixmap
*pix
)
504 WMReleasePixmap(view
->backImage
);
505 view
->backImage
= WMRetainPixmap(pix
);
507 view
->attribFlags
|= CWBackPixmap
;
508 view
->attribFlags
&= ~CWBackPixel
;
509 view
->attribs
.background_pixmap
= pix
->pixmap
;
510 if (view
->flags
.realized
) {
511 XSetWindowBackgroundPixmap(view
->screen
->display
, view
->window
, pix
->pixmap
);
512 XClearWindow(view
->screen
->display
, view
->window
);
516 void W_SetViewCursor(W_View
* view
, Cursor cursor
)
518 view
->cursor
= cursor
;
519 if (W_VIEW_REALIZED(view
)) {
520 XDefineCursor(W_VIEW_DISPLAY(view
), W_VIEW_DRAWABLE(view
), cursor
);
522 view
->attribFlags
|= CWCursor
;
523 view
->attribs
.cursor
= cursor
;
527 W_View
*W_FocusedViewOfToplevel(W_View
* view
)
529 WMScreen
*scr
= view
->screen
;
532 for (info
= scr
->focusInfo
; info
!= NULL
; info
= info
->next
)
533 if (view
== info
->toplevel
)
539 return info
->focused
;
542 void W_SetFocusOfTopLevel(W_View
* toplevel
, W_View
* view
)
544 WMScreen
*scr
= toplevel
->screen
;
548 for (info
= scr
->focusInfo
; info
!= NULL
; info
= info
->next
)
549 if (toplevel
== info
->toplevel
)
553 info
= wmalloc(sizeof(W_FocusInfo
));
554 info
->toplevel
= toplevel
;
555 info
->focused
= view
;
556 info
->next
= scr
->focusInfo
;
557 scr
->focusInfo
= info
;
559 event
.xfocus
.mode
= NotifyNormal
;
560 event
.xfocus
.detail
= NotifyDetailNone
;
562 /* simulate FocusOut event */
563 event
.xfocus
.type
= FocusOut
;
564 W_DispatchMessage(info
->focused
, &event
);
566 info
->focused
= view
;
569 /* simulate FocusIn event */
570 event
.xfocus
.type
= FocusIn
;
571 W_DispatchMessage(view
, &event
);
575 void W_BroadcastMessage(W_View
* targetParent
, XEvent
* event
)
579 target
= targetParent
->childrenList
;
580 while (target
!= NULL
) {
581 W_DispatchMessage(target
, event
);
583 target
= target
->nextSister
;
587 void W_DispatchMessage(W_View
* target
, XEvent
* event
)
589 if (target
->window
== None
)
591 event
->xclient
.window
= target
->window
;
592 event
->xclient
.display
= target
->screen
->display
;
594 WMHandleEvent(event
);
596 XSendEvent(target->screen->display, target->window, False,
597 SubstructureNotifyMask, event);
601 WMView
*W_RetainView(WMView
* view
)
608 void W_ReleaseView(WMView
* view
)
612 if (view
->refCount
< 1) {
617 WMWidget
*WMWidgetOfView(WMView
* view
)
622 WMSize
WMGetViewSize(WMView
* view
)
627 WMPoint
WMGetViewPosition(WMView
* view
)
632 void WMSetViewNotifySizeChanges(WMView
* view
, Bool flag
)
634 view
->flags
.notifySizeChanged
= ((flag
== 0) ? 0 : 1);
637 Window
WMViewXID(WMView
* view
)
642 WMPoint
WMGetViewScreenPosition(WMView
* view
)
644 WMScreen
*scr
= W_VIEW_SCREEN(view
);
646 int x
, y
, topX
, topY
;
651 while (topView
->parent
&& topView
->parent
!= scr
->rootView
)
652 topView
= topView
->parent
;
654 if (!XGetGeometry(scr
->display
, W_VIEW_DRAWABLE(topView
), &foo
, &topX
, &topY
, &bar
, &bar
, &bar
, &bar
)) {
658 XTranslateCoordinates(scr
->display
, W_VIEW_DRAWABLE(view
), scr
->rootWin
, 0, 0, &x
, &y
, &foo
);
660 return wmkpoint(x
- topX
, y
- topY
);
663 static void resizedParent(void *self
, WMNotification
* notif
)
665 WMSize size
= WMGetViewSize((WMView
*) WMGetNotificationObject(notif
));
666 WMView
*view
= (WMView
*) self
;
668 W_MoveView(view
, view
->leftOffs
, view
->topOffs
);
669 W_ResizeView(view
, size
.width
- (view
->leftOffs
+ view
->rightOffs
),
670 size
.height
- (view
->topOffs
+ view
->bottomOffs
));
673 void WMSetViewExpandsToParent(WMView
* view
, int leftOffs
, int topOffs
, int rightOffs
, int bottomOffs
)
675 WMSize size
= view
->parent
->size
;
677 view
->topOffs
= topOffs
;
678 view
->bottomOffs
= bottomOffs
;
679 view
->leftOffs
= leftOffs
;
680 view
->rightOffs
= rightOffs
;
682 WMAddNotificationObserver(resizedParent
, view
, WMViewSizeDidChangeNotification
, view
->parent
);
683 WMSetViewNotifySizeChanges(view
->parent
, True
);
685 W_MoveView(view
, leftOffs
, topOffs
);
686 W_ResizeView(view
, size
.width
- (leftOffs
+ rightOffs
), size
.height
- (topOffs
+ bottomOffs
));