New helper function get_default_image
[wmaker-crm.git] / WINGs / wwindow.c
blob53b98e8982c4df79ea9c4c25a723ab8085a81814
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 win->widgetClass = WC_Window;
140 win->view = W_CreateTopView(screen);
141 if (!win->view) {
142 wfree(win);
143 return NULL;
145 win->view->self = win;
147 win->view->delegate = &_WindowViewDelegate;
149 win->wname = wstrdup(name);
151 /* add to the window list of the screen (application) */
152 win->nextPtr = screen->windowList;
153 screen->windowList = win;
155 WMCreateEventHandler(win->view, ExposureMask | StructureNotifyMask
156 | ClientMessageMask | FocusChangeMask, handleEvents, win);
158 W_ResizeView(win->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
160 WMAddNotificationObserver(realizeObserver, win, WMViewRealizedNotification, win->view);
162 win->flags.style = style;
164 win->level = WMNormalWindowLevel;
166 /* kluge. Find a better solution */
167 W_SetFocusOfTopLevel(win->view, win->view);
169 return win;
172 static void setWindowTitle(WMWindow * win, const char *title)
174 WMScreen *scr = win->view->screen;
175 XTextProperty property;
176 int result;
178 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
179 if (result == XNoMemory || result == XLocaleNotSupported) {
180 wwarning("window title conversion error... using STRING encoding");
181 XStoreName(scr->display, win->view->window, title);
182 } else {
183 XSetWMName(scr->display, win->view->window, &property);
184 if (property.value)
185 XFree(property.value);
188 XChangeProperty(scr->display, win->view->window,
189 scr->netwmName, scr->utf8String, 8,
190 PropModeReplace, (unsigned char *)title, strlen(title));
193 static void setMiniwindowTitle(WMWindow * win, const char *title)
195 WMScreen *scr = win->view->screen;
196 XTextProperty property;
197 int result;
199 result = XmbTextListToTextProperty(scr->display, (char **)&title, 1, XStdICCTextStyle, &property);
200 if (result == XNoMemory || result == XLocaleNotSupported) {
201 wwarning("icon title conversion error..using STRING encoding");
202 XSetIconName(scr->display, win->view->window, title);
203 } else {
204 XSetWMIconName(scr->display, win->view->window, &property);
205 if (property.value)
206 XFree(property.value);
209 XChangeProperty(scr->display, win->view->window,
210 scr->netwmIconName, scr->utf8String, 8,
211 PropModeReplace, (unsigned char *)title, strlen(title));
214 static void setMiniwindow(WMWindow *win, RImage *image)
216 WMScreen *scr = win->view->screen;
217 long *data;
218 int x, y;
219 int o;
221 if (!image)
222 return;
224 data = wmalloc((image->width * image->height + 2) * sizeof(long));
226 o = 0;
227 data[o++] = image->width;
228 data[o++] = image->height;
230 for (y = 0; y < image->height; y++) {
231 for (x = 0; x < image->width; x++) {
232 long pixel;
233 int offs = (x + y * image->width);
235 if (image->format == RRGBFormat)
236 pixel = image->data[offs * 3] << 16 | image->data[offs * 3 + 1] << 8
237 | image->data[offs * 3 + 2];
238 else
239 pixel = image->data[offs * 4] << 16 | image->data[offs * 4 + 1] << 8
240 | image->data[offs * 4 + 2] | image->data[offs * 4 + 3] << 24;
242 data[o++] = pixel;
246 XChangeProperty(scr->display, win->view->window, scr->netwmIcon,
247 XA_CARDINAL, 32, PropModeReplace,
248 (unsigned char *)data, (image->width * image->height + 2));
250 wfree(data);
253 void WMSetWindowTitle(WMWindow * win, char *title)
255 if (win->title != NULL)
256 wfree(win->title);
257 if (title != NULL)
258 win->title = wstrdup(title);
259 else
260 win->title = NULL;
262 if (win->view->flags.realized) {
263 setWindowTitle(win, title);
267 void WMSetWindowCloseAction(WMWindow * win, WMAction * action, void *clientData)
269 Atom *atoms = NULL;
270 Atom *newAtoms;
271 int count;
272 WMScreen *scr = win->view->screen;
274 if (win->view->flags.realized) {
275 if (action && !win->closeAction) {
276 if (!XGetWMProtocols(scr->display, win->view->window, &atoms, &count)) {
277 count = 0;
279 newAtoms = wmalloc((count + 1) * sizeof(Atom));
280 if (count > 0)
281 memcpy(newAtoms, atoms, count * sizeof(Atom));
282 newAtoms[count++] = scr->deleteWindowAtom;
283 XSetWMProtocols(scr->display, win->view->window, newAtoms, count);
284 if (atoms)
285 XFree(atoms);
286 wfree(newAtoms);
287 } else if (!action && win->closeAction) {
288 int i, ncount;
290 if (XGetWMProtocols(scr->display, win->view->window, &atoms, &count) && count > 0) {
291 newAtoms = wmalloc((count - 1) * sizeof(Atom));
292 ncount = 0;
293 for (i = 0; i < count; i++) {
294 if (atoms[i] != scr->deleteWindowAtom) {
295 newAtoms[i] = atoms[i];
296 ncount++;
299 XSetWMProtocols(scr->display, win->view->window, newAtoms, ncount);
300 if (atoms)
301 XFree(atoms);
302 wfree(newAtoms);
306 win->closeAction = action;
307 win->closeData = clientData;
310 static void willResizeWindow(W_ViewDelegate * self, WMView * view, unsigned *width, unsigned *height)
312 WMWindow *win = (WMWindow *) view->self;
314 if (win->minSize.width > 0 && win->minSize.height > 0) {
315 if (*width < win->minSize.width)
316 *width = win->minSize.width;
317 if (*height < win->minSize.height)
318 *height = win->minSize.height;
321 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
322 if (*width > win->maxSize.width)
323 *width = win->maxSize.width;
324 if (*height > win->maxSize.height)
325 *height = win->maxSize.height;
329 static void setSizeHints(WMWindow * win)
331 XSizeHints *hints;
333 hints = XAllocSizeHints();
334 if (!hints) {
335 wwarning("could not allocate memory for window size hints");
336 return;
339 hints->flags = 0;
341 if (win->flags.setPPos) {
342 hints->flags |= PPosition;
343 hints->x = win->ppos.x;
344 hints->y = win->ppos.y;
346 if (win->flags.setUPos) {
347 hints->flags |= USPosition;
348 hints->x = win->upos.x;
349 hints->y = win->upos.y;
351 if (win->minSize.width > 0 && win->minSize.height > 0) {
352 hints->flags |= PMinSize;
353 hints->min_width = win->minSize.width;
354 hints->min_height = win->minSize.height;
356 if (win->maxSize.width > 0 && win->maxSize.height > 0) {
357 hints->flags |= PMaxSize;
358 hints->max_width = win->maxSize.width;
359 hints->max_height = win->maxSize.height;
361 if (win->baseSize.width > 0 && win->baseSize.height > 0) {
362 hints->flags |= PBaseSize;
363 hints->base_width = win->baseSize.width;
364 hints->base_height = win->baseSize.height;
366 if (win->resizeIncrement.width > 0 && win->resizeIncrement.height > 0) {
367 hints->flags |= PResizeInc;
368 hints->width_inc = win->resizeIncrement.width;
369 hints->height_inc = win->resizeIncrement.height;
371 if (win->flags.setAspect) {
372 hints->flags |= PAspect;
373 hints->min_aspect.x = win->minAspect.x;
374 hints->min_aspect.y = win->minAspect.y;
375 hints->max_aspect.x = win->maxAspect.x;
376 hints->max_aspect.y = win->maxAspect.y;
379 if (hints->flags) {
380 XSetWMNormalHints(win->view->screen->display, win->view->window, hints);
382 XFree(hints);
385 static void writeGNUstepWMAttr(WMScreen * scr, Window window, GNUstepWMAttributes * attr)
387 unsigned long data[9];
389 /* handle idiot compilers where array of CARD32 != struct of CARD32 */
390 data[0] = attr->flags;
391 data[1] = attr->window_style;
392 data[2] = attr->window_level;
393 data[3] = 0; /* reserved */
394 /* The X protocol says XIDs are 32bit */
395 data[4] = attr->miniaturize_pixmap;
396 data[5] = attr->close_pixmap;
397 data[6] = attr->miniaturize_mask;
398 data[7] = attr->close_mask;
399 data[8] = attr->extra_flags;
400 XChangeProperty(scr->display, window, scr->attribsAtom, scr->attribsAtom,
401 32, PropModeReplace, (unsigned char *)data, 9);
404 static void setWindowMakerHints(WMWindow * win)
406 GNUstepWMAttributes attribs;
407 WMScreen *scr = WMWidgetScreen(win);
409 memset(&attribs, 0, sizeof(GNUstepWMAttributes));
410 attribs.flags = GSWindowStyleAttr | GSWindowLevelAttr | GSExtraFlagsAttr;
411 attribs.window_style = win->flags.style;
412 attribs.window_level = win->level;
413 if (win->flags.documentEdited)
414 attribs.extra_flags = GSDocumentEditedFlag;
415 else
416 attribs.extra_flags = 0;
418 writeGNUstepWMAttr(scr, win->view->window, &attribs);
421 static void realizeWindow(WMWindow * win)
423 XWMHints *hints;
424 XClassHint *classHint;
425 WMScreen *scr = win->view->screen;
426 Atom atoms[4];
427 int count;
429 classHint = XAllocClassHint();
430 classHint->res_name = win->wname;
431 classHint->res_class = WMGetApplicationName();
432 XSetClassHint(scr->display, win->view->window, classHint);
433 XFree(classHint);
435 hints = XAllocWMHints();
436 hints->flags = 0;
437 if (!scr->aflags.simpleApplication) {
438 hints->flags |= WindowGroupHint;
439 hints->window_group = scr->groupLeader;
441 if (win->miniImage) {
442 hints->flags |= IconPixmapHint;
443 hints->icon_pixmap = WMGetPixmapXID(win->miniImage);
444 hints->icon_mask = WMGetPixmapMaskXID(win->miniImage);
445 if (hints->icon_mask != None) {
446 hints->flags |= IconMaskHint;
449 if (hints->flags != 0)
450 XSetWMHints(scr->display, win->view->window, hints);
451 XFree(hints);
453 count = 0;
454 if (win->closeAction) {
455 atoms[count++] = scr->deleteWindowAtom;
458 if (count > 0)
459 XSetWMProtocols(scr->display, win->view->window, atoms, count);
461 if (win->title || win->miniTitle)
462 XmbSetWMProperties(scr->display, win->view->window, win->title,
463 win->miniTitle, NULL, 0, NULL, NULL, NULL);
465 setWindowMakerHints(win);
467 setSizeHints(win);
469 if (win->owner) {
470 XSetTransientForHint(scr->display, win->view->window, win->owner->view->window);
473 if (win->title)
474 setWindowTitle(win, win->title);
477 void WMSetWindowAspectRatio(WMWindow * win, int minX, int minY, int maxX, int maxY)
479 win->flags.setAspect = 1;
480 win->minAspect.x = minX;
481 win->minAspect.y = minY;
482 win->maxAspect.x = maxX;
483 win->maxAspect.y = maxY;
484 if (win->view->flags.realized)
485 setSizeHints(win);
488 void WMSetWindowInitialPosition(WMWindow * win, int x, int y)
490 win->flags.setPPos = 1;
491 win->ppos.x = x;
492 win->ppos.y = y;
493 if (win->view->flags.realized)
494 setSizeHints(win);
495 WMMoveWidget(win, x, y);
498 void WMSetWindowUserPosition(WMWindow * win, int x, int y)
500 win->flags.setUPos = 1;
501 win->upos.x = x;
502 win->upos.y = y;
503 if (win->view->flags.realized)
504 setSizeHints(win);
505 WMMoveWidget(win, x, y);
508 void WMSetWindowMinSize(WMWindow * win, unsigned width, unsigned height)
510 win->minSize.width = width;
511 win->minSize.height = height;
512 if (win->view->flags.realized)
513 setSizeHints(win);
516 void WMSetWindowMaxSize(WMWindow * win, unsigned width, unsigned height)
518 win->maxSize.width = width;
519 win->maxSize.height = height;
520 if (win->view->flags.realized)
521 setSizeHints(win);
524 void WMSetWindowBaseSize(WMWindow * win, unsigned width, unsigned height)
526 /* TODO: validate sizes */
527 win->baseSize.width = width;
528 win->baseSize.height = height;
529 if (win->view->flags.realized)
530 setSizeHints(win);
533 void WMSetWindowResizeIncrements(WMWindow * win, unsigned wIncr, unsigned hIncr)
535 win->resizeIncrement.width = wIncr;
536 win->resizeIncrement.height = hIncr;
537 if (win->view->flags.realized)
538 setSizeHints(win);
541 void WMSetWindowLevel(WMWindow * win, int level)
543 win->level = level;
544 if (win->view->flags.realized)
545 setWindowMakerHints(win);
548 void WMSetWindowDocumentEdited(WMWindow * win, Bool flag)
550 flag = ((flag == 0) ? 0 : 1);
551 if (win->flags.documentEdited != flag) {
552 win->flags.documentEdited = flag;
553 if (win->view->flags.realized)
554 setWindowMakerHints(win);
558 void WMSetWindowMiniwindowImage(WMWindow * win, RImage * image)
560 if (win->view->flags.realized)
561 setMiniwindow(win, image);
564 void WMSetWindowMiniwindowPixmap(WMWindow * win, WMPixmap * pixmap)
566 if ((win->miniImage && !pixmap) || (!win->miniImage && pixmap)) {
567 if (win->miniImage)
568 WMReleasePixmap(win->miniImage);
570 if (pixmap)
571 win->miniImage = WMRetainPixmap(pixmap);
572 else
573 win->miniImage = NULL;
575 if (win->view->flags.realized) {
576 XWMHints *hints;
578 hints = XGetWMHints(win->view->screen->display, win->view->window);
579 if (!hints) {
580 hints = XAllocWMHints();
581 if (!hints) {
582 wwarning("could not allocate memory for WM hints");
583 return;
585 hints->flags = 0;
587 if (pixmap) {
588 hints->flags |= IconPixmapHint;
589 hints->icon_pixmap = WMGetPixmapXID(pixmap);
590 hints->icon_mask = WMGetPixmapMaskXID(pixmap);
591 if (hints->icon_mask != None) {
592 hints->flags |= IconMaskHint;
595 XSetWMHints(win->view->screen->display, win->view->window, hints);
596 XFree(hints);
601 void WMSetWindowMiniwindowTitle(WMWindow * win, char *title)
603 if ((win->miniTitle && !title) || (!win->miniTitle && title)
604 || (title && win->miniTitle && strcoll(title, win->miniTitle) != 0)) {
605 if (win->miniTitle)
606 wfree(win->miniTitle);
608 if (title)
609 win->miniTitle = wstrdup(title);
610 else
611 win->miniTitle = NULL;
613 if (win->view->flags.realized) {
614 setMiniwindowTitle(win, title);
619 void WMCloseWindow(WMWindow * win)
621 WMUnmapWidget(win);
622 /* withdraw the window */
623 if (win->view->flags.realized)
624 XWithdrawWindow(win->view->screen->display, win->view->window, win->view->screen->screen);
627 static void handleEvents(XEvent * event, void *clientData)
629 _Window *win = (_Window *) clientData;
630 W_View *view = win->view;
632 switch (event->type) {
633 case ClientMessage:
634 if (event->xclient.message_type == win->view->screen->protocolsAtom
635 && event->xclient.format == 32
636 && event->xclient.data.l[0] == win->view->screen->deleteWindowAtom) {
638 if (win->closeAction) {
639 (*win->closeAction) (win, win->closeData);
642 break;
644 * was causing windows to ignore commands like closeWindow
645 * after the windows is iconized/restored or a workspace change
646 * if this is really needed, put the MapNotify portion too and
647 * fix the restack bug in wmaker
648 case UnmapNotify:
649 WMUnmapWidget(win);
650 break;
652 case MapNotify:
653 WMMapWidget(win);
654 break;
657 case DestroyNotify:
658 destroyWindow(win);
659 break;
661 case ConfigureNotify:
662 if (event->xconfigure.width != view->size.width || event->xconfigure.height != view->size.height) {
664 view->size.width = event->xconfigure.width;
665 view->size.height = event->xconfigure.height;
667 if (view->flags.notifySizeChanged) {
668 WMPostNotificationName(WMViewSizeDidChangeNotification, view, NULL);
671 if (event->xconfigure.x != view->pos.x || event->xconfigure.y != view->pos.y) {
673 if (event->xconfigure.send_event) {
674 view->pos.x = event->xconfigure.x;
675 view->pos.y = event->xconfigure.y;
676 } else {
677 Window foo;
679 XTranslateCoordinates(view->screen->display,
680 view->window, view->screen->rootWin,
681 event->xconfigure.x, event->xconfigure.y,
682 &view->pos.x, &view->pos.y, &foo);
685 break;
689 static void destroyWindow(_Window * win)
691 WMScreen *scr = win->view->screen;
693 WMRemoveNotificationObserver(win);
695 if (scr->windowList == win) {
696 scr->windowList = scr->windowList->nextPtr;
697 } else {
698 WMWindow *ptr;
699 ptr = scr->windowList;
701 if (ptr) {
702 while (ptr->nextPtr) {
703 if (ptr->nextPtr == win) {
704 ptr->nextPtr = ptr->nextPtr->nextPtr;
705 break;
707 ptr = ptr->nextPtr;
712 if (win->title) {
713 wfree(win->title);
716 if (win->miniTitle) {
717 wfree(win->miniTitle);
720 if (win->miniImage) {
721 WMReleasePixmap(win->miniImage);
724 if (win->wname)
725 wfree(win->wname);
727 wfree(win);