- Added support for NET_WM_NAME/NET_WM_ICON_NAME
[wmaker-crm.git] / src / screen.c
blob85079d954e0185791a87771beaaf6bc2528e0a37
1 /* screen.c - screen management
3 * Window Maker window manager
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
23 #include "wconfig.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
29 #include <X11/Xlib.h>
30 #include <X11/Xutil.h>
31 #include <X11/Xatom.h>
32 #ifdef SHAPE
33 #include <X11/extensions/shape.h>
34 #endif
35 #ifdef KEEP_XKB_LOCK_STATUS
36 #include <X11/XKBlib.h>
37 #endif /* KEEP_XKB_LOCK_STATUS */
39 #include <wraster.h>
41 #include "WindowMaker.h"
42 #include "def_pixmaps.h"
43 #include "screen.h"
44 #include "texture.h"
45 #include "pixmap.h"
46 #include "menu.h"
47 #include "funcs.h"
48 #include "actions.h"
49 #include "properties.h"
50 #include "dock.h"
51 #include "resources.h"
52 #include "workspace.h"
53 #include "session.h"
54 #include "balloon.h"
55 #include "geomview.h"
56 #ifdef NETWM_HINTS
57 # include "wmspec.h"
58 #endif
60 #include "xinerama.h"
62 #include <WINGs/WUtil.h>
64 #include "defaults.h"
67 #ifdef LITE
68 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
69 |SubstructureNotifyMask|PointerMotionMask \
70 |SubstructureRedirectMask|KeyPressMask|KeyReleaseMask)
71 #else
72 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
73 |SubstructureNotifyMask|PointerMotionMask \
74 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
75 |KeyPressMask|KeyReleaseMask)
76 #endif
78 /**** Global variables ****/
80 extern Cursor wCursor[WCUR_LAST];
81 extern WPreferences wPreferences;
82 extern Atom _XA_WINDOWMAKER_STATE;
83 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
86 extern int wScreenCount;
88 #ifdef KEEP_XKB_LOCK_STATUS
89 extern int wXkbSupported;
90 #endif
92 extern WDDomain *WDWindowMaker;
95 /**** Local ****/
97 #define STIPPLE_WIDTH 2
98 #define STIPPLE_HEIGHT 2
99 static char STIPPLE_DATA[] = {0x02, 0x01};
101 static int CantManageScreen = 0;
103 static WMPropList *dApplications = NULL;
104 static WMPropList *dWorkspace;
105 static WMPropList *dDock;
106 static WMPropList *dClip;
109 static void
110 make_keys()
112 if (dApplications!=NULL)
113 return;
115 dApplications = WMCreatePLString("Applications");
116 dWorkspace = WMCreatePLString("Workspace");
117 dDock = WMCreatePLString("Dock");
118 dClip = WMCreatePLString("Clip");
123 *----------------------------------------------------------------------
124 * alreadyRunningError--
125 * X error handler used to catch errors when trying to do
126 * XSelectInput() on the root window. These errors probably mean that
127 * there already is some other window manager running.
129 * Returns:
130 * Nothing, unless something really evil happens...
132 * Side effects:
133 * CantManageScreen is set to 1;
134 *----------------------------------------------------------------------
136 static int
137 alreadyRunningError(Display *dpy, XErrorEvent *error)
139 CantManageScreen = 1;
140 return -1;
145 *----------------------------------------------------------------------
146 * allocButtonPixmaps--
147 * Allocate pixmaps used on window operation buttons (those in the
148 * titlebar). The pixmaps are linked to the program. If XPM is supported
149 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
151 * Returns:
152 * Nothing
154 * Side effects:
155 * Allocates shared pixmaps for the screen. These pixmaps should
156 * not be freed by anybody.
157 *----------------------------------------------------------------------
159 static void
160 allocButtonPixmaps(WScreen *scr)
162 WPixmap *pix;
164 /* create predefined pixmaps */
165 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
166 if (pix)
167 pix->shared = 1;
168 scr->b_pixmaps[WBUT_CLOSE] = pix;
170 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
171 if (pix)
172 pix->shared = 1;
173 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
175 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
176 if (pix)
177 pix->shared = 1;
178 scr->b_pixmaps[WBUT_ICONIFY] = pix;
179 #ifdef XKB_BUTTON_HINT
180 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
181 if (pix)
182 pix->shared = 1;
183 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
184 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
185 if (pix)
186 pix->shared = 1;
187 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
188 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
189 if (pix)
190 pix->shared = 1;
191 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
192 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
193 if (pix)
194 pix->shared = 1;
195 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
196 #endif
199 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
200 if (pix)
201 pix->shared = 1;
202 scr->b_pixmaps[WBUT_KILL] = pix;
206 static void
207 draw_dot(WScreen *scr, Drawable d, int x, int y, GC gc)
209 XSetForeground(dpy, gc, scr->black_pixel);
210 XDrawLine(dpy, d, gc, x, y, x+1, y);
211 XDrawPoint(dpy, d, gc, x, y+1);
212 XSetForeground(dpy, gc, scr->white_pixel);
213 XDrawLine(dpy, d, gc, x+2, y, x+2, y+1);
214 XDrawPoint(dpy, d, gc, x+1, y+1);
218 static WPixmap*
219 make3Dots(WScreen *scr)
221 WPixmap *wpix;
222 GC gc2, gc;
223 XGCValues gcv;
224 Pixmap pix, mask;
226 gc = scr->copy_gc;
227 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
228 wPreferences.icon_size, scr->w_depth);
229 XSetForeground(dpy, gc, scr->black_pixel);
230 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size,
231 wPreferences.icon_size);
232 XSetForeground(dpy, gc, scr->white_pixel);
233 draw_dot(scr, pix, 4, wPreferences.icon_size-6, gc);
234 draw_dot(scr, pix, 9, wPreferences.icon_size-6, gc);
235 draw_dot(scr, pix, 14, wPreferences.icon_size-6, gc);
237 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size,
238 wPreferences.icon_size, 1);
239 gcv.foreground = 0;
240 gcv.graphics_exposures = False;
241 gc2 = XCreateGC(dpy, mask, GCForeground|GCGraphicsExposures, &gcv);
242 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size,
243 wPreferences.icon_size);
244 XSetForeground(dpy, gc2, 1);
245 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size-6, 3, 2);
246 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size-6, 3, 2);
247 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size-6, 3, 2);
249 XFreeGC(dpy, gc2);
251 wpix = wPixmapCreate(scr, pix, mask);
252 wpix->shared = 1;
254 return wpix;
258 static void
259 allocGCs(WScreen *scr)
261 XGCValues gcv;
262 XColor color;
263 int gcm;
265 scr->stipple_bitmap =
266 XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH,
267 STIPPLE_HEIGHT);
269 gcv.stipple = scr->stipple_bitmap;
270 gcv.foreground = scr->white_pixel;
271 gcv.fill_style = FillStippled;
272 gcv.graphics_exposures = False;
273 gcm = GCForeground|GCStipple|GCFillStyle|GCGraphicsExposures;
274 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
277 /* selected icon border GCs */
278 gcv.function = GXcopy;
279 gcv.foreground = scr->white_pixel;
280 gcv.background = scr->black_pixel;
281 gcv.line_width = 1;
282 gcv.line_style = LineDoubleDash;
283 gcv.fill_style = FillSolid;
284 gcv.dash_offset = 0;
285 gcv.dashes = 4;
286 gcv.graphics_exposures = False;
288 gcm = GCFunction | GCGraphicsExposures;
289 gcm |= GCForeground | GCBackground;
290 gcm |= GCLineWidth | GCLineStyle;
291 gcm |= GCFillStyle;
292 gcm |= GCDashOffset | GCDashList;
294 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
296 scr->menu_title_color[0] = WMRetainColor(scr->white);
298 /* don't retain scr->black here because we may alter its alpha */
299 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
300 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
302 /* frame GC */
303 wGetColor(scr, DEF_FRAME_COLOR, &color);
304 gcv.function = GXxor;
305 /* this will raise the probability of the XORed color being different
306 * of the original color in PseudoColor when not all color cells are
307 * initialized */
308 if (DefaultVisual(dpy, scr->screen)->class==PseudoColor)
309 gcv.plane_mask = (1<<(scr->depth-1))|1;
310 else
311 gcv.plane_mask = AllPlanes;
312 gcv.foreground = color.pixel;
313 if (gcv.foreground == 0)
314 gcv.foreground = 1;
315 gcv.line_width = DEF_FRAME_THICKNESS;
316 gcv.subwindow_mode = IncludeInferiors;
317 gcv.graphics_exposures = False;
318 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground|GCGraphicsExposures
319 |GCFunction|GCSubwindowMode|GCLineWidth
320 |GCPlaneMask, &gcv);
322 /* line GC */
323 gcv.foreground = color.pixel;
325 if (gcv.foreground == 0)
326 /* XOR:ing with a zero is not going to be of much use, so
327 in that case, we somewhat arbitrarily xor with 17 instead. */
328 gcv.foreground = 17;
330 gcv.function = GXxor;
331 gcv.subwindow_mode = IncludeInferiors;
332 gcv.line_width = 1;
333 gcv.cap_style = CapRound;
334 gcv.graphics_exposures = False;
335 gcm = GCForeground|GCFunction|GCSubwindowMode|GCLineWidth|GCCapStyle
336 |GCGraphicsExposures;
337 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
339 scr->line_pixel = gcv.foreground;
341 /* copy GC */
342 gcv.foreground = scr->white_pixel;
343 gcv.background = scr->black_pixel;
344 gcv.graphics_exposures = False;
345 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground|GCBackground
346 |GCGraphicsExposures, &gcv);
348 /* misc drawing GC */
349 gcv.graphics_exposures = False;
350 gcm = GCGraphicsExposures;
351 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
353 assert (scr->stipple_bitmap!=None);
356 /* mono GC */
357 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
362 static void
363 createPixmaps(WScreen *scr)
365 WPixmap *pix;
366 RImage *image;
368 /* load pixmaps */
369 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_RADIO_INDICATOR_XBM_DATA,
370 (char*)MENU_RADIO_INDICATOR_XBM_DATA,
371 MENU_RADIO_INDICATOR_XBM_SIZE,
372 MENU_RADIO_INDICATOR_XBM_SIZE,
373 scr->black_pixel, scr->white_pixel);
374 if (pix!=NULL)
375 pix->shared = 1;
376 scr->menu_radio_indicator = pix;
379 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_CHECK_INDICATOR_XBM_DATA,
380 (char*)MENU_CHECK_INDICATOR_XBM_DATA,
381 MENU_CHECK_INDICATOR_XBM_SIZE,
382 MENU_CHECK_INDICATOR_XBM_SIZE,
383 scr->black_pixel, scr->white_pixel);
384 if (pix!=NULL)
385 pix->shared = 1;
386 scr->menu_check_indicator = pix;
388 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_MINI_INDICATOR_XBM_DATA,
389 (char*)MENU_MINI_INDICATOR_XBM_DATA,
390 MENU_MINI_INDICATOR_XBM_SIZE,
391 MENU_MINI_INDICATOR_XBM_SIZE,
392 scr->black_pixel, scr->white_pixel);
393 if (pix!=NULL)
394 pix->shared = 1;
395 scr->menu_mini_indicator = pix;
397 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_HIDE_INDICATOR_XBM_DATA,
398 (char*)MENU_HIDE_INDICATOR_XBM_DATA,
399 MENU_HIDE_INDICATOR_XBM_SIZE,
400 MENU_HIDE_INDICATOR_XBM_SIZE,
401 scr->black_pixel, scr->white_pixel);
402 if (pix!=NULL)
403 pix->shared = 1;
404 scr->menu_hide_indicator = pix;
406 pix = wPixmapCreateFromXBMData(scr, (char*)MENU_SHADE_INDICATOR_XBM_DATA,
407 (char*)MENU_SHADE_INDICATOR_XBM_DATA,
408 MENU_SHADE_INDICATOR_XBM_SIZE,
409 MENU_SHADE_INDICATOR_XBM_SIZE,
410 scr->black_pixel, scr->white_pixel);
411 if (pix!=NULL)
412 pix->shared = 1;
413 scr->menu_shade_indicator = pix;
416 image = wDefaultGetImage(scr, "Logo", "WMPanel");
418 if (!image) {
419 wwarning(_("could not load logo image for panels: %s"),
420 RMessageForError(RErrorCode));
421 } else {
422 WMSetApplicationIconImage(scr->wmscreen, image);
423 RReleaseImage(image);
426 scr->dock_dots = make3Dots(scr);
428 /* titlebar button pixmaps */
429 allocButtonPixmaps(scr);
434 *----------------------------------------------------------------------
435 * createInternalWindows--
436 * Creates some windows used internally by the program. One to
437 * receive input focus when no other window can get it and another
438 * to display window geometry information during window resize/move.
440 * Returns:
441 * Nothing
443 * Side effects:
444 * Windows are created and some colors are allocated for the
445 * window background.
446 *----------------------------------------------------------------------
448 static void
449 createInternalWindows(WScreen *scr)
451 int vmask;
452 XSetWindowAttributes attribs;
454 /* InputOnly window to get the focus when no other window can get it */
455 vmask = CWEventMask|CWOverrideRedirect;
456 attribs.event_mask = KeyPressMask|FocusChangeMask;
457 attribs.override_redirect = True;
458 scr->no_focus_win=XCreateWindow(dpy,scr->root_win,-10, -10, 4, 4, 0, 0,
459 InputOnly,CopyFromParent, vmask, &attribs);
460 XSelectInput(dpy, scr->no_focus_win, KeyPressMask|KeyReleaseMask);
461 XMapWindow(dpy, scr->no_focus_win);
463 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
465 /* shadow window for dock buttons */
466 vmask = CWBorderPixel|CWBackPixmap|CWBackPixel|CWCursor|CWSaveUnder|CWOverrideRedirect;
467 attribs.border_pixel = scr->black_pixel;
468 attribs.save_under = True;
469 attribs.override_redirect = True;
470 attribs.background_pixmap = None;
471 attribs.background_pixel = scr->white_pixel;
472 attribs.cursor = wCursor[WCUR_DEFAULT];
473 vmask |= CWColormap;
474 attribs.colormap = scr->w_colormap;
475 scr->dock_shadow =
476 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
477 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent,
478 scr->w_visual, vmask, &attribs);
480 /* workspace name balloon for clip */
481 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
482 |CWBorderPixel;
483 attribs.save_under = True;
484 attribs.override_redirect = True;
485 attribs.colormap = scr->w_colormap;
486 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
487 attribs.border_pixel = 0; /* do not care */
488 scr->clip_balloon =
489 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
490 CopyFromParent, scr->w_visual, vmask, &attribs);
493 /* workspace name */
494 vmask = CWBackPixel|CWSaveUnder|CWOverrideRedirect|CWColormap
495 |CWBorderPixel;
496 attribs.save_under = True;
497 attribs.override_redirect = True;
498 attribs.colormap = scr->w_colormap;
499 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
500 attribs.border_pixel = 0; /* do not care */
501 scr->workspace_name =
502 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
503 CopyFromParent, scr->w_visual, vmask, &attribs);
506 * If the window is clicked without having ButtonPress selected, the
507 * resulting event will have event.xbutton.window == root.
509 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
513 #if 0
514 static Bool
515 aquireManagerSelection(WScreen *scr)
517 char buffer[32];
518 XEvent ev;
519 Time timestamp;
521 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
522 scr->managerAtom = XInternAtom(dpy, buffer, False);
524 /* for race-conditions... */
525 XGrabServer(dpy);
527 /* if there is another manager running, don't try to replace it
528 * (for now, at least) */
529 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
530 XUngrabServer(dpy);
531 return False;
534 /* become the manager for this screen */
536 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1,
537 0, 0, 0);
539 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
540 /* get a timestamp */
541 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom,
542 XA_INTEGER, 32, PropModeAppend, NULL, 0);
543 while (1) {
544 XWindowEvent(dpy, scr->managerWindow, &ev);
545 if (ev.type == PropertyNotify) {
546 timestamp = ev.xproperty.time;
547 break;
550 XSelectInput(dpy, scr->managerWindow, NoEvents);
551 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
553 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
555 XUngrabServer(dpy);
557 /* announce our arrival */
559 ev.xclient.type = ClientMessage;
560 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
561 ev.xclient.destination = scr->root_win;
562 ev.xclient.format = 32;
563 ev.xclient.data.l[0] = timestamp;
564 ev.xclient.data.l[1] = scr->managerAtom;
565 ev.xclient.data.l[2] = scr->managerWindow;
566 ev.xclient.data.l[3] = 0;
567 ev.xclient.data.l[4] = 0;
569 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
570 XSync(dpy, False);
572 return True;
574 #endif
577 *----------------------------------------------------------------------
578 * wScreenInit--
579 * Initializes the window manager for the given screen and
580 * allocates a WScreen descriptor for it. Many resources are allocated
581 * for the screen and the root window is setup appropriately.
583 * Returns:
584 * The WScreen descriptor for the screen.
586 * Side effects:
587 * Many resources are allocated and the IconSize property is
588 * set on the root window.
589 * The program can be aborted if some fatal error occurs.
591 * TODO: User specifiable visual.
592 *----------------------------------------------------------------------
594 WScreen*
595 wScreenInit(int screen_number)
597 WScreen *scr;
598 XIconSize icon_size[1];
599 RContextAttributes rattr;
600 extern int wVisualID;
601 long event_mask;
602 XErrorHandler oldHandler;
603 int i;
605 scr = wmalloc(sizeof(WScreen));
606 memset(scr, 0, sizeof(WScreen));
608 scr->stacking_list = WMCreateTreeBag();
610 /* initialize globals */
611 scr->screen = screen_number;
612 scr->root_win = RootWindow(dpy, screen_number);
613 scr->depth = DefaultDepth(dpy, screen_number);
614 scr->colormap = DefaultColormap(dpy, screen_number);
616 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
617 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
619 wInitXinerama(scr);
621 scr->usableArea = (WArea *)wmalloc(sizeof(WArea)*wXineramaHeads(scr));
622 scr->totalUsableArea = (WArea *)wmalloc(sizeof(WArea)*wXineramaHeads(scr));
624 for (i=0; i<wXineramaHeads(scr); ++i) {
625 WMRect rect = wGetRectForHead(scr, i);
626 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
627 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
628 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
629 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
632 scr->fakeGroupLeaders = WMCreateArray(16);
634 #if 0
635 if (!aquireManagerSelection(scr)) {
636 wfree(scr);
638 return NULL;
640 #endif
641 CantManageScreen = 0;
642 oldHandler = XSetErrorHandler((XErrorHandler)alreadyRunningError);
644 event_mask = EVENT_MASK;
646 if (wPreferences.disable_root_mouse) {
647 event_mask &= ~(ButtonPressMask|ButtonReleaseMask);
650 XSelectInput(dpy, scr->root_win, event_mask);
652 #ifdef KEEP_XKB_LOCK_STATUS
653 /* Only GroupLock doesn't work correctly in my system since right-alt
654 * can change mode while holding it too - ]d
656 if (wXkbSupported) {
657 XkbSelectEvents(dpy,XkbUseCoreKbd,
658 XkbStateNotifyMask,
659 XkbStateNotifyMask);
661 #endif /* KEEP_XKB_LOCK_STATUS */
663 XSync(dpy, False);
664 XSetErrorHandler(oldHandler);
666 if (CantManageScreen) {
667 wfree(scr);
668 return NULL;
671 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
673 /* screen descriptor for raster graphic library */
674 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
675 rattr.render_mode = wPreferences.no_dithering
676 ? RBestMatchRendering
677 : RDitheredRendering;
679 /* if the std colormap stuff works ok, this will be ignored */
680 rattr.colors_per_channel = wPreferences.cmap_size;
681 if (rattr.colors_per_channel<2)
682 rattr.colors_per_channel = 2;
685 /* will only be accounted for in PseudoColor */
686 if (wPreferences.flags.create_stdcmap) {
687 rattr.standard_colormap_mode = RCreateStdColormap;
688 } else {
689 rattr.standard_colormap_mode = RUseStdColormap;
692 if (wVisualID>=0) {
693 rattr.flags |= RC_VisualID;
694 rattr.visualid = wVisualID;
697 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
699 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
700 wwarning(RMessageForError(RErrorCode));
702 rattr.flags &= ~RC_StandardColormap;
703 rattr.standard_colormap_mode = RUseStdColormap;
705 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
708 if (!scr->rcontext) {
709 wwarning(_("could not initialize graphics library context: %s"),
710 RMessageForError(RErrorCode));
711 wAbort(False);
712 } else {
713 char **formats;
714 int i = 0;
716 formats = RSupportedFileFormats();
717 if (formats) {
718 for (i=0; formats[i]!=NULL; i++) {
719 if (strcmp(formats[i], "TIFF")==0) {
720 scr->flags.supports_tiff = 1;
721 break;
727 scr->w_win = scr->rcontext->drawable;
728 scr->w_visual = scr->rcontext->visual;
729 scr->w_depth = scr->rcontext->depth;
730 scr->w_colormap = scr->rcontext->cmap;
732 /* create screen descriptor for WINGs */
733 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number,
734 scr->rcontext);
736 if (!scr->wmscreen) {
737 wfatal(_("could not initialize WINGs widget set"));
738 return NULL;
741 scr->black = WMBlackColor(scr->wmscreen);
742 scr->white = WMWhiteColor(scr->wmscreen);
743 scr->gray = WMGrayColor(scr->wmscreen);
744 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
746 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black;*/
747 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white;*/
748 scr->light_pixel = WMColorPixel(scr->gray);
749 scr->dark_pixel = WMColorPixel(scr->darkGray);
752 XColor xcol;
753 /* frame boder color */
754 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
755 scr->frame_border_pixel = xcol.pixel;
758 /* create GCs with default values */
759 allocGCs(scr);
761 /* for our window manager info notice board. Need to
762 * create before reading the defaults, because it will be used there.
764 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10,
765 0, 0, 0);
767 /* read defaults for this screen */
768 wReadDefaults(scr, WDWindowMaker->dictionary);
770 createInternalWindows(scr);
772 #ifdef NETWM_HINTS
773 wNETWMInitStuff(scr);
774 #endif
776 /* create initial workspace */
777 wWorkspaceNew(scr);
779 /* create shared pixmaps */
780 createPixmaps(scr);
782 /* set icon sizes we can accept from clients */
783 icon_size[0].min_width = 8;
784 icon_size[0].min_height = 8;
785 icon_size[0].max_width = wPreferences.icon_size-4;
786 icon_size[0].max_height = wPreferences.icon_size-4;
787 icon_size[0].width_inc = 1;
788 icon_size[0].height_inc = 1;
789 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
791 /* setup WindowMaker protocols property in the root window*/
792 PropSetWMakerProtocols(scr->root_win);
794 /* setup our noticeboard */
795 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
796 XA_WINDOW, 32, PropModeReplace,
797 (unsigned char*)&scr->info_window, 1);
798 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
799 XA_WINDOW, 32, PropModeReplace,
800 (unsigned char*)&scr->info_window, 1);
803 #ifdef BALLOON_TEXT
804 /* initialize balloon text stuff */
805 wBalloonInitialize(scr);
806 #endif
808 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
810 scr->tech_draw_font= XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
812 scr->gview = WCreateGeometryView(scr->wmscreen);
813 WMRealizeWidget(scr->gview);
815 wScreenUpdateUsableArea(scr);
817 return scr;
821 void
822 wScreenUpdateUsableArea(WScreen *scr)
825 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
826 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
827 * border.
830 int i;
831 unsigned long best_area = 0, tmp_area;
832 WArea area;
833 int dock_head = scr->xine_info.primary_head;
835 if (scr->dock) {
836 WMRect rect;
837 rect.pos.x = scr->dock->x_pos;
838 rect.pos.y = scr->dock->y_pos;
839 rect.size.width = wPreferences.icon_size;
840 rect.size.height = wPreferences.icon_size;
841 dock_head = wGetHeadForRect(scr, rect);
844 for (i=0; i<wXineramaHeads(scr); ++i) {
845 WMRect rect = wGetRectForHead(scr, i);
846 scr->totalUsableArea[i].x1 = rect.pos.x;
847 scr->totalUsableArea[i].y1 = rect.pos.y;
848 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
849 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
851 if (scr->dock && dock_head==i &&
852 (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
853 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
855 if (scr->dock->on_right_side) {
856 scr->totalUsableArea[i].x2 -= offset;
857 } else {
858 scr->totalUsableArea[i].x1 += offset;
862 #ifdef NETWM_HINTS
864 WArea area;
865 if (wNETWMGetUsableArea(scr, i, &area)) {
866 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
867 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
868 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
869 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
872 #endif
874 scr->usableArea[i] = scr->totalUsableArea[i];
876 #if 0
877 printf("usableArea[%d]: %d %d %d %d\n", i,
878 scr->usableArea[i].x1, scr->usableArea[i].x2,
879 scr->usableArea[i].y1, scr->usableArea[i].y2);
880 #endif
882 if (wPreferences.no_window_over_icons) {
883 if (wPreferences.icon_yard & IY_VERT) {
884 if (wPreferences.icon_yard & IY_RIGHT) {
885 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
886 } else {
887 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
889 } else {
890 if (wPreferences.icon_yard & IY_TOP) {
891 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
892 } else {
893 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
898 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width/2) {
899 scr->totalUsableArea[i].x1 = rect.pos.x;
900 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
903 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height/2) {
904 scr->totalUsableArea[i].y1 = rect.pos.y;
905 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
908 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
909 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
911 if (tmp_area > best_area) {
912 best_area = tmp_area;
913 area = scr->totalUsableArea[i];
917 unsigned size = wPreferences.workspace_border_size;
918 unsigned position = wPreferences.workspace_border_position;
920 if (size>0 && position!=WB_NONE) {
921 if (position & WB_LEFTRIGHT) {
922 scr->totalUsableArea[i].x1 += size;
923 scr->totalUsableArea[i].x2 -= size;
925 if (position & WB_TOPBOTTOM) {
926 scr->totalUsableArea[i].y1 += size;
927 scr->totalUsableArea[i].y2 -= size;
933 #ifdef NETWM_HINTS
934 wNETWMUpdateWorkarea(scr, area);
935 #endif
937 if (wPreferences.auto_arrange_icons) {
938 wArrangeIcons(scr, True);
942 #if 0
943 void
944 wScreenUpdateUsableArea(WScreen *scr)
946 scr->totalUsableArea = scr->usableArea;
948 if (scr->dock && (!scr->dock->lowered
949 || wPreferences.no_window_over_dock)) {
951 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
953 if (scr->dock->on_right_side) {
954 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2,
955 scr->scr_width - offset);
956 } else {
957 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
961 if (wPreferences.no_window_over_icons) {
962 if (wPreferences.icon_yard & IY_VERT) {
964 if (!(wPreferences.icon_yard & IY_RIGHT)) {
965 scr->totalUsableArea.x1 += wPreferences.icon_size;
966 } else {
967 scr->totalUsableArea.x2 -= wPreferences.icon_size;
969 } else {
971 if (wPreferences.icon_yard & IY_TOP) {
972 scr->totalUsableArea.y1 += wPreferences.icon_size;
973 } else {
974 scr->totalUsableArea.y2 -= wPreferences.icon_size;
979 #ifdef NETWM_HINTS
981 WArea area;
982 if (wNETWMGetUsableArea(scr, &area)) {
983 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
984 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
985 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
986 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
989 #endif
991 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width/2) {
992 scr->totalUsableArea.x2 = scr->usableArea.x2;
993 scr->totalUsableArea.x1 = scr->usableArea.x1;
995 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height/2) {
996 scr->totalUsableArea.y2 = scr->usableArea.y2;
997 scr->totalUsableArea.y1 = scr->usableArea.y1;
1000 #ifdef NETWM_HINTS
1001 wNETWMUpdateWorkarea(scr);
1002 #endif
1005 unsigned size = wPreferences.workspace_border_size;
1006 unsigned position = wPreferences.workspace_border_position;
1008 if (size>0 && position!=WB_NONE) {
1009 if (position & WB_LEFTRIGHT) {
1010 scr->totalUsableArea.x1 += size;
1011 scr->totalUsableArea.x2 -= size;
1013 if (position & WB_TOPBOTTOM) {
1014 scr->totalUsableArea.y1 += size;
1015 scr->totalUsableArea.y2 -= size;
1020 if (wPreferences.auto_arrange_icons) {
1021 wArrangeIcons(scr, True);
1024 #endif
1027 void
1028 wScreenRestoreState(WScreen *scr)
1030 WMPropList *state;
1031 char *path;
1034 #ifndef LITE
1035 OpenRootMenu(scr, -10000, -10000, False);
1036 wMenuUnmap(scr->root_menu);
1037 #endif
1039 make_keys();
1041 if (wScreenCount == 1) {
1042 path = wdefaultspathfordomain("WMState");
1043 } else {
1044 char buf[16];
1045 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1046 path = wdefaultspathfordomain(buf);
1048 scr->session_state = WMReadPropListFromFile(path);
1049 wfree(path);
1050 if (!scr->session_state && wScreenCount>1) {
1051 path = wdefaultspathfordomain("WMState");
1052 scr->session_state = WMReadPropListFromFile(path);
1053 wfree(path);
1056 if (!scr->session_state) {
1057 scr->session_state = WMCreatePLDictionary(NULL, NULL);
1060 if (!wPreferences.flags.nodock) {
1061 state = WMGetFromPLDictionary(scr->session_state, dDock);
1062 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
1065 if (!wPreferences.flags.noclip) {
1066 state = WMGetFromPLDictionary(scr->session_state, dClip);
1067 scr->clip_icon = wClipRestoreState(scr, state);
1070 wWorkspaceRestoreState(scr);
1072 #ifdef VIRTUAL_DESKTOP
1073 /* create inputonly windows at the border of screen */
1074 wWorkspaceManageEdge(scr);
1075 #endif
1077 wScreenUpdateUsableArea(scr);
1081 void
1082 wScreenSaveState(WScreen *scr)
1084 WWindow *wwin;
1085 char *str;
1086 WMPropList *old_state, *foo;
1088 make_keys();
1090 /* save state of windows */
1091 wwin = scr->focused_window;
1092 while (wwin) {
1093 wWindowSaveState(wwin);
1094 wwin = wwin->prev;
1098 if (wPreferences.flags.noupdates)
1099 return;
1102 old_state = scr->session_state;
1103 scr->session_state = WMCreatePLDictionary(NULL, NULL);
1105 WMPLSetCaseSensitive(True);
1107 /* save dock state to file */
1108 if (!wPreferences.flags.nodock) {
1109 wDockSaveState(scr, old_state);
1110 } else {
1111 if ((foo = WMGetFromPLDictionary(old_state, dDock))!=NULL) {
1112 WMPutInPLDictionary(scr->session_state, dDock, foo);
1115 if (!wPreferences.flags.noclip) {
1116 wClipSaveState(scr);
1117 } else {
1118 if ((foo = WMGetFromPLDictionary(old_state, dClip))!=NULL) {
1119 WMPutInPLDictionary(scr->session_state, dClip, foo);
1123 wWorkspaceSaveState(scr, old_state);
1125 if (wPreferences.save_session_on_exit) {
1126 wSessionSaveState(scr);
1127 } else {
1128 if ((foo = WMGetFromPLDictionary(old_state, dApplications))!=NULL) {
1129 WMPutInPLDictionary(scr->session_state, dApplications, foo);
1131 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace))!=NULL) {
1132 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
1136 /* clean up */
1137 WMPLSetCaseSensitive(False);
1139 wMenuSaveState(scr);
1141 if (wScreenCount == 1) {
1142 str = wdefaultspathfordomain("WMState");
1143 } else {
1144 char buf[16];
1145 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1146 str = wdefaultspathfordomain(buf);
1148 if (!WMWritePropListToFile(scr->session_state, str, True)) {
1149 wsyserror(_("could not save session state in %s"), str);
1151 wfree(str);
1152 WMReleasePropList(old_state);
1158 wScreenBringInside(WScreen *scr, int *x, int *y, int width, int height)
1160 int moved = 0;
1161 int tol_w, tol_h;
1163 * With respect to the head that contains most of the window.
1165 int sx1, sy1, sx2, sy2;
1167 WMRect rect;
1168 int head, flags;
1170 rect.pos.x = *x;
1171 rect.pos.y = *y;
1172 rect.size.width = width;
1173 rect.size.height = height;
1175 head = wGetRectPlacementInfo(scr, rect, &flags);
1176 rect = wGetRectForHead(scr, head);
1178 sx1 = rect.pos.x;
1179 sy1 = rect.pos.y;
1180 sx2 = sx1 + rect.size.width;
1181 sy2 = sy1 + rect.size.height;
1183 #if 0 /* NOTE: gives funky group movement */
1184 if (flags & XFLAG_MULTIPLE) {
1186 * since we span multiple heads, pull window totaly inside
1188 if (*x < sx1)
1189 *x = sx1, moved = 1;
1190 else if (*x + width > sx2)
1191 *x = sx2 - width, moved = 1;
1193 if (*y < sy1)
1194 *y = sy1, moved = 1;
1195 else if (*y + height > sy2)
1196 *y = sy2 - height, moved = 1;
1198 return moved;
1200 #endif
1202 if (width > 20)
1203 tol_w = width/2;
1204 else
1205 tol_w = 20;
1207 if (height > 20)
1208 tol_h = height/2;
1209 else
1210 tol_h = 20;
1212 if (*x + width < sx1 + 10)
1213 *x = sx1 - tol_w, moved = 1;
1214 else if (*x >= sx2 - 10)
1215 *x = sx2 - tol_w - 1, moved = 1;
1217 if (*y < sy1 - height + 10)
1218 *y = sy1 - tol_h, moved = 1;
1219 else if (*y >= sy2 - 10)
1220 *y = sy2 - tol_h - 1, moved = 1;
1222 return moved;
1228 wScreenKeepInside(WScreen *scr, int *x, int *y, int width, int height)
1230 int moved = 0;
1231 int sx1, sy1, sx2, sy2;
1232 WMRect rect;
1233 int head;
1235 rect.pos.x = *x;
1236 rect.pos.y = *y;
1237 rect.size.width = width;
1238 rect.size.height = height;
1240 head = wGetHeadForRect(scr, rect);
1241 rect = wGetRectForHead(scr, head);
1243 sx1 = rect.pos.x;
1244 sy1 = rect.pos.y;
1245 sx2 = sx1 + rect.size.width;
1246 sy2 = sy1 + rect.size.height;
1248 if (*x < sx1)
1249 *x = sx1, moved = 1;
1250 else if (*x + width > sx2)
1251 *x = sx2 - width, moved = 1;
1253 if (*y < sy1)
1254 *y = sy1, moved = 1;
1255 else if (*y + height > sy2)
1256 *y = sy2 - height, moved = 1;
1258 return moved;