Port WM2 branch onto next
[wmaker-crm.git] / WINGs / wwindow.c
blob6814650c0319e15a5e7b49172553579c54b3682f
2 #include <X11/Xmd.h>
4 #include "WINGsP.h"
6 #include <X11/Xatom.h>
8 typedef struct W_Window {
9 W_Class widgetClass;
10 W_View *view;
12 struct W_Window *nextPtr; /* next in the window list */
14 struct W_Window *owner;
16 char *title;
18 WMPixmap *miniImage; /* miniwindow */
19 char *miniTitle;
21 char *wname;
23 WMSize resizeIncrement;
24 WMSize baseSize;
25 WMSize minSize;
26 WMSize maxSize;
27 WMPoint minAspect;
28 WMPoint maxAspect;
30 WMPoint upos;
31 WMPoint ppos;
33 WMAction *closeAction;
34 void *closeData;
36 int level;
38 struct {
39 unsigned style:4;
40 unsigned configured:1;
41 unsigned documentEdited:1;
43 unsigned setUPos:1;
44 unsigned setPPos:1;
45 unsigned setAspect:1;
46 } flags;
47 } _Window;
49 typedef struct {
50 CARD32 flags;
51 CARD32 window_style;
52 CARD32 window_level;
53 CARD32 reserved;
54 Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
55 Pixmap close_pixmap; /* pixmap for close button */
56 Pixmap miniaturize_mask; /* miniaturize pixmap mask */
57 Pixmap close_mask; /* close pixmap mask */
58 CARD32 extra_flags;
59 } GNUstepWMAttributes;
61 #define GSWindowStyleAttr (1<<0)
62 #define GSWindowLevelAttr (1<<1)
63 #define GSMiniaturizePixmapAttr (1<<3)
64 #define GSClosePixmapAttr (1<<4)
65 #define GSMiniaturizeMaskAttr (1<<5)
66 #define GSCloseMaskAttr (1<<6)
67 #define GSExtraFlagsAttr (1<<7)
69 /* extra flags */
70 #define GSDocumentEditedFlag (1<<0)
71 #define GSNoApplicationIconFlag (1<<5)
73 #define WMFHideOtherApplications 10
74 #define WMFHideApplication 12
76 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned *, unsigned *);
78 struct W_ViewDelegate _WindowViewDelegate = {
79 NULL,
80 NULL,
81 NULL,
82 NULL,
83 willResizeWindow
86 #define DEFAULT_WIDTH 400
87 #define DEFAULT_HEIGHT 180
88 #define DEFAULT_TITLE ""
90 static void destroyWindow(_Window * win);
92 static void handleEvents();
94 static void realizeWindow();
96 static void realizeObserver(void *self, WMNotification * not)
98 realizeWindow(self);
101 WMWindow *WMCreatePanelWithStyleForWindow(WMWindow * owner, char *name, int style)
103 WMWindow *win;
105 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
106 win->owner = owner;
108 return win;
111 WMWindow *WMCreatePanelForWindow(WMWindow * owner, char *name)
113 return WMCreatePanelWithStyleForWindow(owner, name,
114 WMTitledWindowMask | WMClosableWindowMask | WMResizableWindowMask);
117 void WMChangePanelOwner(WMWindow * win, WMWindow * newOwner)
119 win->owner = newOwner;
121 if (win->view->flags.realized && newOwner) {
122 XSetTransientForHint(win->view->screen->display, win->view->window, newOwner->view->window);
126 WMWindow *WMCreateWindow(WMScreen * screen, char *name)
128 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
129 | WMClosableWindowMask
130 | WMMiniaturizableWindowMask | WMResizableWindowMask);
133 WMWindow *WMCreateWindowWithStyle(WMScreen * screen, char *name, int style)
135 _Window *win;
137 win = wmalloc(sizeof(_Window));
138 memset(win, 0, sizeof(_Window));
140 win->widgetClass = WC_Window;
142 win->view = W_CreateTopView(screen);
143 if (!win->view) {
144 wfree(win);
145 return NULL;
147 win->view->self = win;
149 win->view->delegate = &_WindowViewDelegate;
151 win->wname = wstrdup(name);
153 /* add to the window list of the screen (application) */
154 win->nextPtr = screen->windowList;
155 screen->windowList = win;
157 WMCreateEventHandler(win->view, ExposureMask | StructureNotifyMask
158 | ClientMessageMask | FocusChangeMask, handleEvents, win);
160 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
162 WMAddNotificationObserver(realizeObserver, win, WMViewRealizedNotification, win->view);
164 win->flags.style = style;
166 win->level = WMNormalWindowLevel;
168 /* kluge. Find a better solution */
169 W_SetFocusOfTopLevel(win->view, win->view);
171 return win;
174 static void setWindowTitle(WMWindow * win, const char *title)
176 WMScreen *scr = win->view->screen;
177 XTextProperty property;
178 int result;
180 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
181 if (result == XNoMemory || result == XLocaleNotSupported) {
182 wwarning("window title conversion error... using STRING encoding");
183 XStoreName(scr->display, win->view->window, title);
184 } else {
185 XSetWMName(scr->display, win->view->window, &property);
186 if (property.value)
187 XFree(property.value);
190 XChangeProperty(scr->display, win->view->window,
191 scr->netwmName, scr->utf8String, 8,
192 PropModeReplace, (unsigned char *)title, strlen(title));
195 static void setMiniwindowTitle(WMWindow *win, const char *title)
197 WMScreen *scr = win->view->screen;
198 XTextProperty property;
199 int result;
201 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
202 if (result == XNoMemory || result == XLocaleNotSupported) {
203 wwarning("icon title conversion error..using STRING encoding");
204 XSetIconName(scr->display, win->view->window, title);
205 } else {
206 XSetWMIconName(scr->display, win->view->window, &property);
207 if (property.value)
208 XFree(property.value);
211 XChangeProperty(scr->display, win->view->window,
212 scr->netwmIconName, scr->utf8String, 8,
213 PropModeReplace, (unsigned char *)title, strlen(title));
216 static void setMiniwindow(WMWindow *win, cairo_surface_t *image)
218 WMScreen *scr= win->view->screen;
219 long *data;
220 int x, y;
221 int o;
222 int w, h;
223 cairo_surface_t *buffer;
225 if (!image)
226 return;
228 w= cairo_image_surface_get_width(image);
229 h= cairo_image_surface_get_height(image);
231 data= wmalloc((w * h + 2) * sizeof(long));
233 data[0] = w;
234 data[1] = h;
236 buffer= cairo_image_surface_create_for_data((unsigned char *)(data + 2), CAIRO_FORMAT_ARGB32,
237 w, h, w*4);
239 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
240 XA_CARDINAL, 32, PropModeReplace,
241 (unsigned char *)data, (w * h + 2));
243 cairo_surface_destroy(buffer);
244 wfree(data);
247 void WMSetWindowTitle(WMWindow *win, char *title)
249 if (win->title != NULL)
250 wfree(win->title);
251 if (title != NULL)
252 win->title = wstrdup(title);
253 else
254 win->title = NULL;
256 if (win->view->flags.realized) {
257 setWindowTitle(win, title);
261 void WMSetWindowCloseAction(WMWindow *win, WMAction *action, void *clientData)
263 Atom *atoms = NULL;
264 Atom *newAtoms;
265 int count;
266 WMScreen *scr = win->view->screen;
268 if (win->view->flags.realized) {
269 if (action && !win->closeAction) {
270 if (!XGetWMProtocols(scr->display, win->view->window, &atoms, &count)) {
271 count = 0;
273 newAtoms = wmalloc((count + 1) * sizeof(Atom));
274 if (count > 0)
275 memcpy(newAtoms, atoms, count * sizeof(Atom));
276 newAtoms[count++] = scr->deleteWindowAtom;
277 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
278 if (atoms)
279 XFree(atoms);
280 wfree(newAtoms);
281 } else if (!action && win->closeAction) {
282 int i, ncount;
284 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
285 newAtoms = wmalloc((count - 1) * sizeof(Atom));
286 ncount = 0;
287 for (i = 0; i < count; i++) {
288 if (atoms[i] != scr->deleteWindowAtom) {
289 newAtoms[i] = atoms[i];
290 ncount++;
293 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
294 if (atoms)
295 XFree(atoms);
296 wfree(newAtoms);
300 win->closeAction = action;
301 win->closeData = clientData;
304 static void willResizeWindow(W_ViewDelegate * self, WMView * view, unsigned *width, unsigned *height)
306 WMWindow *win = (WMWindow *) view->self;
308 if (win->minSize.width > 0 && win->minSize.height > 0) {
309 if (*width < win->minSize.width)
310 *width = win->minSize.width;
311 if (*height < win->minSize.height)
312 *height = win->minSize.height;
315 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
316 if (*width > win->maxSize.width)
317 *width = win->maxSize.width;
318 if (*height > win->maxSize.height)
319 *height = win->maxSize.height;
323 static void setSizeHints(WMWindow * win)
325 XSizeHints *hints;
327 hints = XAllocSizeHints();
328 if (!hints) {
329 wwarning("could not allocate memory for window size hints");
330 return;
333 hints->flags = 0;
335 if (win->flags.setPPos) {
336 hints->flags |= PPosition;
337 hints->x = win->ppos.x;
338 hints->y = win->ppos.y;
340 if (win->flags.setUPos) {
341 hints->flags |= USPosition;
342 hints->x = win->upos.x;
343 hints->y = win->upos.y;
345 if (win->minSize.width > 0 && win->minSize.height > 0) {
346 hints->flags |= PMinSize;
347 hints->min_width = win->minSize.width;
348 hints->min_height = win->minSize.height;
350 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
351 hints->flags |= PMaxSize;
352 hints->max_width = win->maxSize.width;
353 hints->max_height = win->maxSize.height;
355 if (win->baseSize.width > 0 && win->baseSize.height > 0) {
356 hints->flags |= PBaseSize;
357 hints->base_width = win->baseSize.width;
358 hints->base_height = win->baseSize.height;
360 if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) {
361 hints->flags |= PResizeInc;
362 hints->width_inc = win->resizeIncrement.width;
363 hints->height_inc = win->resizeIncrement.height;
365 if (win->flags.setAspect) {
366 hints->flags |= PAspect;
367 hints->min_aspect.x = win->minAspect.x;
368 hints->min_aspect.y = win->minAspect.y;
369 hints->max_aspect.x = win->maxAspect.x;
370 hints->max_aspect.y = win->maxAspect.y;
373 if (hints->flags) {
374 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
376 XFree(hints);
379 static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
381 unsigned long data[9];
383 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
384 data[0] = attr->flags;
385 data[1] = attr->window_style;
386 data[2] = attr->window_level;
387 data[3] = 0; /* reserved */
388 /* The X protocol says XIDs are 32bit */
389 data[4] = attr->miniaturize_pixmap;
390 data[5] = attr->close_pixmap;
391 data[6] = attr->miniaturize_mask;
392 data[7] = attr->close_mask;
393 data[8] = attr->extra_flags;
394 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
395 32, PropModeReplace, (unsigned char *)data, 9);
398 static void setWindowMakerHints(WMWindow * win)
400 GNUstepWMAttributes attribs;
401 WMScreen *scr = WMWidgetScreen(win);
403 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
404 attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr;
405 attribs.window_style = win->flags.style;
406 attribs.window_level = win->level;
407 if (win->flags.documentEdited)
408 attribs.extra_flags = GSDocumentEditedFlag;
409 else
410 attribs.extra_flags = 0;
412 writeGNUstepWMAttr(scr, win->view->window, &attribs);
415 static void realizeWindow(WMWindow * win)
417 XWMHints *hints;
418 XClassHint *classHint;
419 WMScreen *scr = win->view->screen;
420 Atom atoms[4];
421 int count;
423 classHint = XAllocClassHint();
424 classHint->res_name = win->wname;
425 classHint->res_class = WMGetApplicationName();
426 XSetClassHint(scr->display, win->view->window, classHint);
427 XFree(classHint);
429 hints = XAllocWMHints();
430 hints->flags = 0;
431 if (!scr->aflags.simpleApplication) {
432 hints->flags |= WindowGroupHint;
433 hints->window_group = scr->groupLeader;
435 if (win->miniImage) {
436 hints->flags |= IconPixmapHint;
437 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
438 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
439 if (hints->icon_mask != None) {
440 hints->flags |= IconMaskHint;
443 if (hints->flags != 0)
444 XSetWMHints(scr->display, win->view->window, hints);
445 XFree(hints);
447 count = 0;
448 if (win->closeAction) {
449 atoms[count++] = scr->deleteWindowAtom;
452 if (count > 0)
453 XSetWMProtocols(scr->display, win->view->window, atoms, count);
455 if (win->title || win->miniTitle)
456 XmbSetWMProperties(scr->display, win->view->window, win->title,
457 win->miniTitle, NULL, 0, NULL, NULL, NULL);
459 setWindowMakerHints(win);
461 setSizeHints(win);
463 if (win->owner) {
464 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
467 if (win->title)
468 setWindowTitle(win, win->title);
471 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
473 win->flags.setAspect = 1;
474 win->minAspect.x = minX;
475 win->minAspect.y = minY;
476 win->maxAspect.x = maxX;
477 win->maxAspect.y = maxY;
478 if (win->view->flags.realized)
479 setSizeHints(win);
482 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
484 win->flags.setPPos = 1;
485 win->ppos.x = x;
486 win->ppos.y = y;
487 if (win->view->flags.realized)
488 setSizeHints(win);
489 WMMoveWidget(win, x, y);
492 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
494 win->flags.setUPos = 1;
495 win->upos.x = x;
496 win->upos.y = y;
497 if (win->view->flags.realized)
498 setSizeHints(win);
499 WMMoveWidget(win, x, y);
502 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
504 win->minSize.width = width;
505 win->minSize.height = height;
506 if (win->view->flags.realized)
507 setSizeHints(win);
510 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
512 win->maxSize.width = width;
513 win->maxSize.height = height;
514 if (win->view->flags.realized)
515 setSizeHints(win);
518 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
520 /* TODO: validate sizes */
521 win->baseSize.width = width;
522 win->baseSize.height = height;
523 if (win->view->flags.realized)
524 setSizeHints(win);
527 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
529 win->resizeIncrement.width = wIncr;
530 win->resizeIncrement.height = hIncr;
531 if (win->view->flags.realized)
532 setSizeHints(win);
535 void WMSetWindowLevel(WMWindow * win, int level)
537 win->level = level;
538 if (win->view->flags.realized)
539 setWindowMakerHints(win);
542 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
544 flag = ((flag == 0) ? 0 : 1);
545 if (win->flags.documentEdited != flag) {
546 win->flags.documentEdited = flag;
547 if (win->view->flags.realized)
548 setWindowMakerHints(win);
552 void WMSetWindowMiniwindowImage(WMWindow * win, cairo_surface_t * image)
554 if (win->view->flags.realized)
555 setMiniwindow(win, image);
558 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
560 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
561 if (win->miniImage)
562 WMReleasePixmap(win->miniImage);
564 if (pixmap)
565 win->miniImage = WMRetainPixmap(pixmap);
566 else
567 win->miniImage = NULL;
569 if (win->view->flags.realized) {
570 XWMHints *hints;
572 hints = XGetWMHints(win->view->screen->display, win->view->window);
573 if (!hints) {
574 hints = XAllocWMHints();
575 if (!hints) {
576 wwarning("could not allocate memory for WM hints");
577 return;
579 hints->flags = 0;
581 if (pixmap) {
582 hints->flags |= IconPixmapHint;
583 hints->icon_pixmap = WMGetPixmapXID(pixmap);
584 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
585 if (hints->icon_mask != None) {
586 hints->flags |= IconMaskHint;
589 XSetWMHints(win->view->screen->display, win->view->window, hints);
590 XFree(hints);
595 void WMSetWindowMiniwindowTitle(WMWindow * win, char *title)
597 if ((win->miniTitle && !title) || (!win->miniTitle && title)
598 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0)) {
599 if (win->miniTitle)
600 wfree(win->miniTitle);
602 if (title)
603 win->miniTitle = wstrdup(title);
604 else
605 win->miniTitle = NULL;
607 if (win->view->flags.realized) {
608 setMiniwindowTitle(win, title);
613 void WMCloseWindow(WMWindow * win)
615 WMUnmapWidget(win);
616 /* withdraw the window */
617 if (win->view->flags.realized)
618 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
621 static void handleEvents(XEvent * event, void *clientData)
623 _Window *win = (_Window *) clientData;
624 W_View *view = win->view;
626 switch (event->type) {
627 case ClientMessage:
628 if (event->xclient.message_type == win->view->screen->protocolsAtom
629 && event->xclient.format == 32
630 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
632 if (win->closeAction) {
633 (*win->closeAction) (win, win->closeData);
636 break;
638 * was causing windows to ignore commands like closeWindow
639 * after the windows is iconized/restored or a workspace change
640 * if this is really needed, put the MapNotify portion too and
641 * fix the restack bug in wmaker
642 case UnmapNotify:
643 WMUnmapWidget(win);
644 break;
646 case MapNotify:
647 WMMapWidget(win);
648 break;
651 case DestroyNotify:
652 destroyWindow(win);
653 break;
655 case ConfigureNotify:
656 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
658 view->size.width = event->xconfigure.width;
659 view->size.height = event->xconfigure.height;
661 if (view->flags.notifySizeChanged) {
662 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
665 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
667 if (event->xconfigure.send_event) {
668 view->pos.x = event->xconfigure.x;
669 view->pos.y = event->xconfigure.y;
670 } else {
671 Window foo;
673 XTranslateCoordinates(view->screen->display,
674 view->window, view->screen->rootWin,
675 event->xconfigure.x, event->xconfigure.y,
676 &view->pos.x, &view->pos.y, &foo);
679 break;
683 static void destroyWindow(_Window * win)
685 WMScreen *scr = win->view->screen;
687 WMRemoveNotificationObserver(win);
689 if (scr->windowList == win) {
690 scr->windowList = scr->windowList->nextPtr;
691 } else {
692 WMWindow *ptr;
693 ptr = scr->windowList;
695 if (ptr) {
696 while (ptr->nextPtr) {
697 if (ptr->nextPtr == win) {
698 ptr->nextPtr = ptr->nextPtr->nextPtr;
699 break;
701 ptr = ptr->nextPtr;
706 if (win->title) {
707 wfree(win->title);
710 if (win->miniTitle) {
711 wfree(win->miniTitle);
714 if (win->miniImage) {
715 WMReleasePixmap(win->miniImage);
718 if (win->wname)
719 wfree(win->wname);
721 wfree(win);