- Fixed wrong call to XChangeProperty() when setting _NET_WM_ICON
[wmaker-crm.git] / WINGs / wwindow.c
blob7e2c290a05a2ee0f33eac5eb050ce3ef126b91ea
2 #include <X11/Xmd.h>
4 #include "WINGsP.h"
6 #include <X11/Xatom.h>
9 typedef struct W_Window {
10 W_Class widgetClass;
11 W_View *view;
13 struct W_Window *nextPtr; /* next in the window list */
15 struct W_Window *owner;
17 char *title;
19 WMPixmap *miniImage; /* miniwindow */
20 char *miniTitle;
22 char *wname;
24 WMSize resizeIncrement;
25 WMSize baseSize;
26 WMSize minSize;
27 WMSize maxSize;
28 WMPoint minAspect;
29 WMPoint maxAspect;
31 WMPoint upos;
32 WMPoint ppos;
34 WMAction *closeAction;
35 void *closeData;
37 int level;
39 struct {
40 unsigned style:4;
41 unsigned configured:1;
42 unsigned documentEdited:1;
44 unsigned setUPos:1;
45 unsigned setPPos:1;
46 unsigned setAspect:1;
47 } flags;
48 } _Window;
52 typedef struct {
53 CARD32 flags;
54 CARD32 window_style;
55 CARD32 window_level;
56 CARD32 reserved;
57 Pixmap miniaturize_pixmap; /* pixmap for miniaturize button */
58 Pixmap close_pixmap; /* pixmap for close button */
59 Pixmap miniaturize_mask; /* miniaturize pixmap mask */
60 Pixmap close_mask; /* close pixmap mask */
61 CARD32 extra_flags;
62 } GNUstepWMAttributes;
64 #define GSWindowStyleAttr (1<<0)
65 #define GSWindowLevelAttr (1<<1)
66 #define GSMiniaturizePixmapAttr (1<<3)
67 #define GSClosePixmapAttr (1<<4)
68 #define GSMiniaturizeMaskAttr (1<<5)
69 #define GSCloseMaskAttr (1<<6)
70 #define GSExtraFlagsAttr (1<<7)
72 /* extra flags */
73 #define GSDocumentEditedFlag (1<<0)
74 #define GSNoApplicationIconFlag (1<<5)
76 #define WMFHideOtherApplications 10
77 #define WMFHideApplication 12
81 static void willResizeWindow(W_ViewDelegate *, WMView *, unsigned*, unsigned*);
83 struct W_ViewDelegate _WindowViewDelegate = {
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 willResizeWindow
92 #define DEFAULT_WIDTH 400
93 #define DEFAULT_HEIGHT 180
94 #define DEFAULT_TITLE ""
97 static void destroyWindow(_Window *win);
99 static void handleEvents();
101 static void realizeWindow();
103 static void
104 realizeObserver(void *self, WMNotification *not)
106 realizeWindow(self);
110 WMWindow*
111 WMCreatePanelWithStyleForWindow(WMWindow *owner, char *name, int style)
113 WMWindow *win;
115 win = WMCreateWindowWithStyle(owner->view->screen, name, style);
116 win->owner = owner;
118 return win;
123 WMWindow*
124 WMCreatePanelForWindow(WMWindow *owner, char *name)
126 return WMCreatePanelWithStyleForWindow(owner, name,
127 WMTitledWindowMask
128 |WMClosableWindowMask
129 |WMResizableWindowMask);
133 void
134 WMChangePanelOwner(WMWindow *win, WMWindow *newOwner)
136 win->owner = newOwner;
138 if (win->view->flags.realized && newOwner) {
139 XSetTransientForHint(win->view->screen->display, win->view->window,
140 newOwner->view->window);
146 WMWindow*
147 WMCreateWindow(WMScreen *screen, char *name)
149 return WMCreateWindowWithStyle(screen, name, WMTitledWindowMask
150 |WMClosableWindowMask
151 |WMMiniaturizableWindowMask
152 |WMResizableWindowMask);
157 WMWindow*
158 WMCreateWindowWithStyle(WMScreen *screen, char *name, int style)
160 _Window *win;
162 win = wmalloc(sizeof(_Window));
163 memset(win, 0, sizeof(_Window));
165 win->widgetClass = WC_Window;
167 win->view = W_CreateTopView(screen);
168 if (!win->view) {
169 wfree(win);
170 return NULL;
172 win->view->self = win;
174 win->view->delegate = &_WindowViewDelegate;
176 win->wname = wstrdup(name);
178 /* add to the window list of the screen (application) */
179 win->nextPtr = screen->windowList;
180 screen->windowList = win;
182 WMCreateEventHandler(win->view, ExposureMask|StructureNotifyMask
183 |ClientMessageMask|FocusChangeMask,
184 handleEvents, win);
186 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
188 WMAddNotificationObserver(realizeObserver, win,
189 WMViewRealizedNotification, win->view);
191 win->flags.style = style;
193 win->level = WMNormalWindowLevel;
195 /* kluge. Find a better solution */
196 W_SetFocusOfTopLevel(win->view, win->view);
198 return win;
203 static void
204 setWindowTitle(WMWindow *win, const char *title)
206 WMScreen *scr= win->view->screen;
207 XTextProperty property;
208 int result;
210 result = XmbTextListToTextProperty(scr->display,
211 (char**)&title, 1, XStdICCTextStyle,
212 &property);
213 if (result == XNoMemory || result == XLocaleNotSupported) {
214 wwarning("window title conversion error... using STRING encoding");
215 XStoreName(scr->display, win->view->window, title);
216 } else {
217 XSetWMName(scr->display, win->view->window, &property);
218 if (property.value)
219 XFree(property.value);
222 XChangeProperty(scr->display, win->view->window,
223 scr->netwmName, scr->utf8String, 8,
224 PropModeReplace, (unsigned char *)title, strlen(title));
228 static void
229 setMiniwindowTitle(WMWindow *win, const char *title)
231 WMScreen *scr= win->view->screen;
232 XTextProperty property;
233 int result;
235 result = XmbTextListToTextProperty(scr->display,
236 (char**)&title, 1, XStdICCTextStyle,
237 &property);
238 if (result == XNoMemory || result == XLocaleNotSupported) {
239 wwarning("icon title conversion error..using STRING encoding");
240 XSetIconName(scr->display, win->view->window, title);
241 } else {
242 XSetWMIconName(scr->display, win->view->window, &property);
243 if (property.value)
244 XFree(property.value);
247 XChangeProperty(scr->display, win->view->window,
248 scr->netwmIconName, scr->utf8String, 8,
249 PropModeReplace, (unsigned char *)title, strlen(title));
253 static void
254 setMiniwindow(WMWindow *win, RImage *image)
256 WMScreen *scr= win->view->screen;
257 CARD32 *data;
258 int x, y;
259 int o;
261 if (!image)
262 return;
264 data = wmalloc((image->width * image->height + 2) * sizeof(CARD32));
266 o= 0;
267 data[o++] = image->width;
268 data[o++] = image->height;
270 for (y= 0; y < image->height; y++) {
271 for (x= 0; x < image->width; x++) {
272 CARD32 pixel;
273 int offs= (x+y*image->width);
275 if (image->format == RRGBFormat)
276 pixel= image->data[offs*3]<<16 | image->data[offs*3+1]<<8 | image->data[offs*3+2];
277 else
278 pixel= image->data[offs*4]<<16 | image->data[offs*4+1]<<8 | image->data[offs*4+2] | image->data[offs*4+3] << 24;
280 data[o++]= pixel;
284 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
285 XA_CARDINAL, 32, PropModeReplace,
286 (unsigned char *)data,
287 (image->width * image->height + 2));
289 wfree(data);
293 void
294 WMSetWindowTitle(WMWindow *win, char *title)
296 if (win->title!=NULL)
297 wfree(win->title);
298 if (title!=NULL)
299 win->title = wstrdup(title);
300 else
301 win->title = NULL;
303 if (win->view->flags.realized) {
304 setWindowTitle(win, title);
311 void
312 WMSetWindowCloseAction(WMWindow *win, WMAction *action, void *clientData)
314 Atom *atoms = NULL;
315 Atom *newAtoms;
316 int count;
317 WMScreen *scr = win->view->screen;
319 if (win->view->flags.realized) {
320 if (action && !win->closeAction) {
321 if (!XGetWMProtocols(scr->display, win->view->window, &atoms,
322 &count)) {
323 count = 0;
325 newAtoms = wmalloc((count+1)*sizeof(Atom));
326 if (count > 0)
327 memcpy(newAtoms, atoms, count*sizeof(Atom));
328 newAtoms[count++] = scr->deleteWindowAtom;
329 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
330 if (atoms)
331 XFree(atoms);
332 wfree(newAtoms);
333 } else if (!action && win->closeAction) {
334 int i, ncount;
336 if (XGetWMProtocols(scr->display, win->view->window, &atoms,
337 &count) && count>0) {
338 newAtoms = wmalloc((count-1)*sizeof(Atom));
339 ncount = 0;
340 for (i=0; i < count; i++) {
341 if (atoms[i]!=scr->deleteWindowAtom) {
342 newAtoms[i] = atoms[i];
343 ncount++;
346 XSetWMProtocols(scr->display, win->view->window, newAtoms,
347 ncount);
348 if (atoms)
349 XFree(atoms);
350 wfree(newAtoms);
354 win->closeAction = action;
355 win->closeData = clientData;
360 static void
361 willResizeWindow(W_ViewDelegate *self, WMView *view,
362 unsigned *width, unsigned *height)
364 WMWindow *win = (WMWindow*)view->self;
366 if (win->minSize.width > 0 && win->minSize.height > 0) {
367 if (*width < win->minSize.width)
368 *width = win->minSize.width;
369 if (*height < win->minSize.height)
370 *height = win->minSize.height;
373 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
374 if (*width > win->maxSize.width)
375 *width = win->maxSize.width;
376 if (*height > win->maxSize.height)
377 *height = win->maxSize.height;
382 static void
383 setSizeHints(WMWindow *win)
385 XSizeHints *hints;
387 hints = XAllocSizeHints();
388 if (!hints) {
389 wwarning("could not allocate memory for window size hints");
390 return;
393 hints->flags = 0;
395 if (win->flags.setPPos) {
396 hints->flags |= PPosition;
397 hints->x = win->ppos.x;
398 hints->y = win->ppos.y;
400 if (win->flags.setUPos) {
401 hints->flags |= USPosition;
402 hints->x = win->upos.x;
403 hints->y = win->upos.y;
405 if (win->minSize.width>0 && win->minSize.height>0) {
406 hints->flags |= PMinSize;
407 hints->min_width = win->minSize.width;
408 hints->min_height = win->minSize.height;
410 if (win->maxSize.width>0 && win->maxSize.height>0) {
411 hints->flags |= PMaxSize;
412 hints->max_width = win->maxSize.width;
413 hints->max_height = win->maxSize.height;
415 if (win->baseSize.width>0 && win->baseSize.height>0) {
416 hints->flags |= PBaseSize;
417 hints->base_width = win->baseSize.width;
418 hints->base_height = win->baseSize.height;
420 if (win->resizeIncrement.width>0 && win->resizeIncrement.height>0) {
421 hints->flags |= PResizeInc;
422 hints->width_inc = win->resizeIncrement.width;
423 hints->height_inc = win->resizeIncrement.height;
425 if (win->flags.setAspect) {
426 hints->flags |= PAspect;
427 hints->min_aspect.x = win->minAspect.x;
428 hints->min_aspect.y = win->minAspect.y;
429 hints->max_aspect.x = win->maxAspect.x;
430 hints->max_aspect.y = win->maxAspect.y;
434 if (hints->flags) {
435 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
437 XFree(hints);
442 static void
443 writeGNUstepWMAttr(WMScreen *scr, Window window, GNUstepWMAttributes *attr)
445 unsigned long data[9];
447 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
448 data[0] = attr->flags;
449 data[1] = attr->window_style;
450 data[2] = attr->window_level;
451 data[3] = 0; /* reserved */
452 /* The X protocol says XIDs are 32bit */
453 data[4] = attr->miniaturize_pixmap;
454 data[5] = attr->close_pixmap;
455 data[6] = attr->miniaturize_mask;
456 data[7] = attr->close_mask;
457 data[8] = attr->extra_flags;
458 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
459 32, PropModeReplace, (unsigned char *)data, 9);
463 static void
464 setWindowMakerHints(WMWindow *win)
466 GNUstepWMAttributes attribs;
467 WMScreen *scr = WMWidgetScreen(win);
469 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
470 attribs.flags = GSWindowStyleAttr|GSWindowLevelAttr|GSExtraFlagsAttr;
471 attribs.window_style = win->flags.style;
472 attribs.window_level = win->level;
473 if (win->flags.documentEdited)
474 attribs.extra_flags = GSDocumentEditedFlag;
475 else
476 attribs.extra_flags = 0;
478 writeGNUstepWMAttr(scr, win->view->window, &attribs);
482 static void
483 realizeWindow(WMWindow *win)
485 XWMHints *hints;
486 XClassHint *classHint;
487 WMScreen *scr = win->view->screen;
488 Atom atoms[4];
489 int count;
491 classHint = XAllocClassHint();
492 classHint->res_name = win->wname;
493 classHint->res_class = WMGetApplicationName();
494 XSetClassHint(scr->display, win->view->window, classHint);
495 XFree(classHint);
497 hints = XAllocWMHints();
498 hints->flags = 0;
499 if (!scr->aflags.simpleApplication) {
500 hints->flags |= WindowGroupHint;
501 hints->window_group = scr->groupLeader;
503 if (win->miniImage) {
504 hints->flags |= IconPixmapHint;
505 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
506 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
507 if (hints->icon_mask != None) {
508 hints->flags |= IconMaskHint;
511 if (hints->flags != 0)
512 XSetWMHints(scr->display, win->view->window, hints);
513 XFree(hints);
515 count = 0;
516 if (win->closeAction) {
517 atoms[count++] = scr->deleteWindowAtom;
520 if (count>0)
521 XSetWMProtocols(scr->display, win->view->window, atoms, count);
523 if (win->title || win->miniTitle)
524 XmbSetWMProperties(scr->display, win->view->window, win->title,
525 win->miniTitle, NULL, 0, NULL, NULL, NULL);
527 setWindowMakerHints(win);
529 setSizeHints(win);
531 if (win->owner) {
532 XSetTransientForHint(scr->display, win->view->window,
533 win->owner->view->window);
536 if (win->title)
537 setWindowTitle(win, win->title);
542 void
543 WMSetWindowAspectRatio(WMWindow *win, int minX, int minY,
544 int maxX, int maxY)
546 win->flags.setAspect = 1;
547 win->minAspect.x = minX;
548 win->minAspect.y = minY;
549 win->maxAspect.x = maxX;
550 win->maxAspect.y = maxY;
551 if (win->view->flags.realized)
552 setSizeHints(win);
557 void
558 WMSetWindowInitialPosition(WMWindow *win, int x, int y)
560 win->flags.setPPos = 1;
561 win->ppos.x = x;
562 win->ppos.y = y;
563 if (win->view->flags.realized)
564 setSizeHints(win);
565 WMMoveWidget(win, x, y);
570 void
571 WMSetWindowUserPosition(WMWindow *win, int x, int y)
573 win->flags.setUPos = 1;
574 win->upos.x = x;
575 win->upos.y = y;
576 if (win->view->flags.realized)
577 setSizeHints(win);
578 WMMoveWidget(win, x, y);
584 void
585 WMSetWindowMinSize(WMWindow *win, unsigned width, unsigned height)
587 win->minSize.width = width;
588 win->minSize.height = height;
589 if (win->view->flags.realized)
590 setSizeHints(win);
595 void
596 WMSetWindowMaxSize(WMWindow *win, unsigned width, unsigned height)
598 win->maxSize.width = width;
599 win->maxSize.height = height;
600 if (win->view->flags.realized)
601 setSizeHints(win);
605 void
606 WMSetWindowBaseSize(WMWindow *win, unsigned width, unsigned height)
608 /* TODO: validate sizes */
609 win->baseSize.width = width;
610 win->baseSize.height = height;
611 if (win->view->flags.realized)
612 setSizeHints(win);
616 void
617 WMSetWindowResizeIncrements(WMWindow *win, unsigned wIncr, unsigned hIncr)
619 win->resizeIncrement.width = wIncr;
620 win->resizeIncrement.height = hIncr;
621 if (win->view->flags.realized)
622 setSizeHints(win);
626 void
627 WMSetWindowLevel(WMWindow *win, int level)
629 win->level = level;
630 if (win->view->flags.realized)
631 setWindowMakerHints(win);
635 void
636 WMSetWindowDocumentEdited(WMWindow *win, Bool flag)
638 flag = ((flag==0) ? 0 : 1);
639 if (win->flags.documentEdited != flag) {
640 win->flags.documentEdited = flag;
641 if (win->view->flags.realized)
642 setWindowMakerHints(win);
647 void
648 WMSetWindowMiniwindowImage(WMWindow *win, RImage *image)
650 if (win->view->flags.realized)
651 setMiniwindow(win, image);
655 void
656 WMSetWindowMiniwindowPixmap(WMWindow *win, WMPixmap *pixmap)
658 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
659 if (win->miniImage)
660 WMReleasePixmap(win->miniImage);
662 if (pixmap)
663 win->miniImage = WMRetainPixmap(pixmap);
664 else
665 win->miniImage = NULL;
667 if (win->view->flags.realized) {
668 XWMHints *hints;
670 hints = XGetWMHints(win->view->screen->display, win->view->window);
671 if (!hints) {
672 hints = XAllocWMHints();
673 if (!hints) {
674 wwarning("could not allocate memory for WM hints");
675 return;
677 hints->flags = 0;
679 if (pixmap) {
680 hints->flags |= IconPixmapHint;
681 hints->icon_pixmap = WMGetPixmapXID(pixmap);
682 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
683 if (hints->icon_mask != None) {
684 hints->flags |= IconMaskHint;
687 XSetWMHints(win->view->screen->display, win->view->window, hints);
688 XFree(hints);
694 void
695 WMSetWindowMiniwindowTitle(WMWindow *win, char *title)
697 if ((win->miniTitle && !title) || (!win->miniTitle && title)
698 || (title && win->miniTitle && strcoll(title, win->miniTitle)!=0)) {
699 if (win->miniTitle)
700 wfree(win->miniTitle);
702 if (title)
703 win->miniTitle = wstrdup(title);
704 else
705 win->miniTitle = NULL;
707 if (win->view->flags.realized) {
708 setMiniwindowTitle(win, title);
714 void
715 WMCloseWindow(WMWindow *win)
717 WMUnmapWidget(win);
718 /* withdraw the window */
719 if (win->view->flags.realized)
720 XWithdrawWindow(win->view->screen->display, win->view->window,
721 win->view->screen->screen);
725 static void
726 handleEvents(XEvent *event, void *clientData)
728 _Window *win = (_Window*)clientData;
729 W_View *view = win->view;
732 switch (event->type) {
733 case ClientMessage:
734 if (event->xclient.message_type == win->view->screen->protocolsAtom
735 && event->xclient.format == 32
736 && event->xclient.data.l[0]==win->view->screen->deleteWindowAtom) {
738 if (win->closeAction) {
739 (*win->closeAction)(win, win->closeData);
742 break;
744 * was causing windows to ignore commands like closeWindow
745 * after the windows is iconized/restored or a workspace change
746 * if this is really needed, put the MapNotify portion too and
747 * fix the restack bug in wmaker
748 case UnmapNotify:
749 WMUnmapWidget(win);
750 break;
752 case MapNotify:
753 WMMapWidget(win);
754 break;
757 case DestroyNotify:
758 destroyWindow(win);
759 break;
761 case ConfigureNotify:
762 if (event->xconfigure.width != view->size.width
763 || event->xconfigure.height != view->size.height) {
765 view->size.width = event->xconfigure.width;
766 view->size.height = event->xconfigure.height;
768 if (view->flags.notifySizeChanged) {
769 WMPostNotificationName(WMViewSizeDidChangeNotification,
770 view, NULL);
773 if (event->xconfigure.x != view->pos.x
774 || event->xconfigure.y != view->pos.y) {
776 if (event->xconfigure.send_event) {
777 view->pos.x = event->xconfigure.x;
778 view->pos.y = event->xconfigure.y;
779 } else {
780 Window foo;
782 XTranslateCoordinates(view->screen->display,
783 view->window, view->screen->rootWin,
784 event->xconfigure.x, event->xconfigure.y,
785 &view->pos.x, &view->pos.y, &foo);
788 break;
795 static void
796 destroyWindow(_Window *win)
798 WMScreen *scr = win->view->screen;
800 WMRemoveNotificationObserver(win);
802 if (scr->windowList == win) {
803 scr->windowList = scr->windowList->nextPtr;
804 } else {
805 WMWindow *ptr;
806 ptr = scr->windowList;
808 if (ptr) {
809 while (ptr->nextPtr) {
810 if (ptr->nextPtr==win) {
811 ptr->nextPtr = ptr->nextPtr->nextPtr;
812 break;
814 ptr = ptr->nextPtr;
819 if (win->title) {
820 wfree(win->title);
823 if (win->miniTitle) {
824 wfree(win->miniTitle);
827 if (win->miniImage) {
828 WMReleasePixmap(win->miniImage);
831 if (win->wname)
832 wfree(win->wname);
834 wfree(win);