Remove LITE config option
[wmaker-crm.git] / src / screen.c
blobe359dcb15e89d1bb8643d139199cb5f4332e7005
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"
66 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
67 |SubstructureNotifyMask|PointerMotionMask \
68 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
69 |KeyPressMask|KeyReleaseMask)
71 /**** Global variables ****/
72 extern Cursor wCursor[WCUR_LAST];
73 extern WPreferences wPreferences;
74 extern Atom _XA_WINDOWMAKER_STATE;
75 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
77 extern int wScreenCount;
79 #ifdef KEEP_XKB_LOCK_STATUS
80 extern int wXkbSupported;
81 #endif
83 extern WDDomain *WDWindowMaker;
85 /**** Local ****/
86 #define STIPPLE_WIDTH 2
87 #define STIPPLE_HEIGHT 2
88 static char STIPPLE_DATA[] = { 0x02, 0x01 };
90 static int CantManageScreen = 0;
92 static WMPropList *dApplications = NULL;
93 static WMPropList *dWorkspace;
94 static WMPropList *dDock;
95 static WMPropList *dClip;
97 static void make_keys()
99 if (dApplications != NULL)
100 return;
102 dApplications = WMCreatePLString("Applications");
103 dWorkspace = WMCreatePLString("Workspace");
104 dDock = WMCreatePLString("Dock");
105 dClip = WMCreatePLString("Clip");
109 *----------------------------------------------------------------------
110 * alreadyRunningError--
111 * X error handler used to catch errors when trying to do
112 * XSelectInput() on the root window. These errors probably mean that
113 * there already is some other window manager running.
115 * Returns:
116 * Nothing, unless something really evil happens...
118 * Side effects:
119 * CantManageScreen is set to 1;
120 *----------------------------------------------------------------------
122 static int alreadyRunningError(Display * dpy, XErrorEvent * error)
124 CantManageScreen = 1;
125 return -1;
129 *----------------------------------------------------------------------
130 * allocButtonPixmaps--
131 * Allocate pixmaps used on window operation buttons (those in the
132 * titlebar). The pixmaps are linked to the program. If XPM is supported
133 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
135 * Returns:
136 * Nothing
138 * Side effects:
139 * Allocates shared pixmaps for the screen. These pixmaps should
140 * not be freed by anybody.
141 *----------------------------------------------------------------------
143 static void allocButtonPixmaps(WScreen * scr)
145 WPixmap *pix;
147 /* create predefined pixmaps */
148 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
149 if (pix)
150 pix->shared = 1;
151 scr->b_pixmaps[WBUT_CLOSE] = pix;
153 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
154 if (pix)
155 pix->shared = 1;
156 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
158 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
159 if (pix)
160 pix->shared = 1;
161 scr->b_pixmaps[WBUT_ICONIFY] = pix;
162 #ifdef XKB_BUTTON_HINT
163 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
164 if (pix)
165 pix->shared = 1;
166 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
167 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
168 if (pix)
169 pix->shared = 1;
170 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
171 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
172 if (pix)
173 pix->shared = 1;
174 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
175 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
176 if (pix)
177 pix->shared = 1;
178 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
179 #endif
181 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
182 if (pix)
183 pix->shared = 1;
184 scr->b_pixmaps[WBUT_KILL] = pix;
187 static void draw_dot(WScreen * scr, Drawable d, int x, int y, GC gc)
189 XSetForeground(dpy, gc, scr->black_pixel);
190 XDrawLine(dpy, d, gc, x, y, x + 1, y);
191 XDrawPoint(dpy, d, gc, x, y + 1);
192 XSetForeground(dpy, gc, scr->white_pixel);
193 XDrawLine(dpy, d, gc, x + 2, y, x + 2, y + 1);
194 XDrawPoint(dpy, d, gc, x + 1, y + 1);
197 static WPixmap *make3Dots(WScreen * scr)
199 WPixmap *wpix;
200 GC gc2, gc;
201 XGCValues gcv;
202 Pixmap pix, mask;
204 gc = scr->copy_gc;
205 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
206 XSetForeground(dpy, gc, scr->black_pixel);
207 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
208 XSetForeground(dpy, gc, scr->white_pixel);
209 draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
210 draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
211 draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
213 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
214 gcv.foreground = 0;
215 gcv.graphics_exposures = False;
216 gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
217 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
218 XSetForeground(dpy, gc2, 1);
219 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
220 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
221 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
223 XFreeGC(dpy, gc2);
225 wpix = wPixmapCreate(scr, pix, mask);
226 wpix->shared = 1;
228 return wpix;
231 static void allocGCs(WScreen * scr)
233 XGCValues gcv;
234 XColor color;
235 int gcm;
237 scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
239 gcv.stipple = scr->stipple_bitmap;
240 gcv.foreground = scr->white_pixel;
241 gcv.fill_style = FillStippled;
242 gcv.graphics_exposures = False;
243 gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
244 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
246 /* selected icon border GCs */
247 gcv.function = GXcopy;
248 gcv.foreground = scr->white_pixel;
249 gcv.background = scr->black_pixel;
250 gcv.line_width = 1;
251 gcv.line_style = LineDoubleDash;
252 gcv.fill_style = FillSolid;
253 gcv.dash_offset = 0;
254 gcv.dashes = 4;
255 gcv.graphics_exposures = False;
257 gcm = GCFunction | GCGraphicsExposures;
258 gcm |= GCForeground | GCBackground;
259 gcm |= GCLineWidth | GCLineStyle;
260 gcm |= GCFillStyle;
261 gcm |= GCDashOffset | GCDashList;
263 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
265 scr->menu_title_color[0] = WMRetainColor(scr->white);
267 /* don't retain scr->black here because we may alter its alpha */
268 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
269 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
271 /* frame GC */
272 wGetColor(scr, DEF_FRAME_COLOR, &color);
273 gcv.function = GXxor;
274 /* this will raise the probability of the XORed color being different
275 * of the original color in PseudoColor when not all color cells are
276 * initialized */
277 if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
278 gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
279 else
280 gcv.plane_mask = AllPlanes;
281 gcv.foreground = color.pixel;
282 if (gcv.foreground == 0)
283 gcv.foreground = 1;
284 gcv.line_width = DEF_FRAME_THICKNESS;
285 gcv.subwindow_mode = IncludeInferiors;
286 gcv.graphics_exposures = False;
287 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
288 | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
290 /* line GC */
291 gcv.foreground = color.pixel;
293 if (gcv.foreground == 0)
294 /* XOR:ing with a zero is not going to be of much use, so
295 in that case, we somewhat arbitrarily xor with 17 instead. */
296 gcv.foreground = 17;
298 gcv.function = GXxor;
299 gcv.subwindow_mode = IncludeInferiors;
300 gcv.line_width = 1;
301 gcv.cap_style = CapRound;
302 gcv.graphics_exposures = False;
303 gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
304 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
306 scr->line_pixel = gcv.foreground;
308 /* copy GC */
309 gcv.foreground = scr->white_pixel;
310 gcv.background = scr->black_pixel;
311 gcv.graphics_exposures = False;
312 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
314 /* misc drawing GC */
315 gcv.graphics_exposures = False;
316 gcm = GCGraphicsExposures;
317 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
319 assert(scr->stipple_bitmap != None);
321 /* mono GC */
322 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
325 static void createPixmaps(WScreen * scr)
327 WPixmap *pix;
328 RImage *image;
330 /* load pixmaps */
331 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_RADIO_INDICATOR_XBM_DATA,
332 (char *)MENU_RADIO_INDICATOR_XBM_DATA,
333 MENU_RADIO_INDICATOR_XBM_SIZE,
334 MENU_RADIO_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
335 if (pix != NULL)
336 pix->shared = 1;
337 scr->menu_radio_indicator = pix;
339 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
340 (char *)MENU_CHECK_INDICATOR_XBM_DATA,
341 MENU_CHECK_INDICATOR_XBM_SIZE,
342 MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
343 if (pix != NULL)
344 pix->shared = 1;
345 scr->menu_check_indicator = pix;
347 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
348 (char *)MENU_MINI_INDICATOR_XBM_DATA,
349 MENU_MINI_INDICATOR_XBM_SIZE,
350 MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
351 if (pix != NULL)
352 pix->shared = 1;
353 scr->menu_mini_indicator = pix;
355 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
356 (char *)MENU_HIDE_INDICATOR_XBM_DATA,
357 MENU_HIDE_INDICATOR_XBM_SIZE,
358 MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
359 if (pix != NULL)
360 pix->shared = 1;
361 scr->menu_hide_indicator = pix;
363 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
364 (char *)MENU_SHADE_INDICATOR_XBM_DATA,
365 MENU_SHADE_INDICATOR_XBM_SIZE,
366 MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
367 if (pix != NULL)
368 pix->shared = 1;
369 scr->menu_shade_indicator = pix;
371 image = wDefaultGetImage(scr, "Logo", "WMPanel");
373 if (!image) {
374 wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
375 } else {
376 WMSetApplicationIconImage(scr->wmscreen, image);
377 RReleaseImage(image);
380 scr->dock_dots = make3Dots(scr);
382 /* titlebar button pixmaps */
383 allocButtonPixmaps(scr);
387 *----------------------------------------------------------------------
388 * createInternalWindows--
389 * Creates some windows used internally by the program. One to
390 * receive input focus when no other window can get it and another
391 * to display window geometry information during window resize/move.
393 * Returns:
394 * Nothing
396 * Side effects:
397 * Windows are created and some colors are allocated for the
398 * window background.
399 *----------------------------------------------------------------------
401 static void createInternalWindows(WScreen * scr)
403 int vmask;
404 XSetWindowAttributes attribs;
406 /* InputOnly window to get the focus when no other window can get it */
407 vmask = CWEventMask | CWOverrideRedirect;
408 attribs.event_mask = KeyPressMask | FocusChangeMask;
409 attribs.override_redirect = True;
410 scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
411 InputOnly, CopyFromParent, vmask, &attribs);
412 XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
413 XMapWindow(dpy, scr->no_focus_win);
415 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
417 /* shadow window for dock buttons */
418 vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
419 attribs.border_pixel = scr->black_pixel;
420 attribs.save_under = True;
421 attribs.override_redirect = True;
422 attribs.background_pixmap = None;
423 attribs.background_pixel = scr->white_pixel;
424 attribs.cursor = wCursor[WCUR_DEFAULT];
425 vmask |= CWColormap;
426 attribs.colormap = scr->w_colormap;
427 scr->dock_shadow =
428 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
429 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
431 /* workspace name balloon for clip */
432 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
433 attribs.save_under = True;
434 attribs.override_redirect = True;
435 attribs.colormap = scr->w_colormap;
436 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
437 attribs.border_pixel = 0; /* do not care */
438 scr->clip_balloon =
439 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
440 CopyFromParent, scr->w_visual, vmask, &attribs);
442 /* workspace name */
443 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
444 attribs.save_under = True;
445 attribs.override_redirect = True;
446 attribs.colormap = scr->w_colormap;
447 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
448 attribs.border_pixel = 0; /* do not care */
449 scr->workspace_name =
450 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
451 CopyFromParent, scr->w_visual, vmask, &attribs);
454 * If the window is clicked without having ButtonPress selected, the
455 * resulting event will have event.xbutton.window == root.
457 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
460 #if 0
461 static Bool aquireManagerSelection(WScreen * scr)
463 char buffer[32];
464 XEvent ev;
465 Time timestamp;
467 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
468 scr->managerAtom = XInternAtom(dpy, buffer, False);
470 /* for race-conditions... */
471 XGrabServer(dpy);
473 /* if there is another manager running, don't try to replace it
474 * (for now, at least) */
475 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
476 XUngrabServer(dpy);
477 return False;
480 /* become the manager for this screen */
482 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1, 0, 0, 0);
484 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
485 /* get a timestamp */
486 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom, XA_INTEGER, 32, PropModeAppend, NULL, 0);
487 while (1) {
488 XWindowEvent(dpy, scr->managerWindow, &ev);
489 if (ev.type == PropertyNotify) {
490 timestamp = ev.xproperty.time;
491 break;
494 XSelectInput(dpy, scr->managerWindow, NoEvents);
495 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
497 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
499 XUngrabServer(dpy);
501 /* announce our arrival */
503 ev.xclient.type = ClientMessage;
504 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
505 ev.xclient.destination = scr->root_win;
506 ev.xclient.format = 32;
507 ev.xclient.data.l[0] = timestamp;
508 ev.xclient.data.l[1] = scr->managerAtom;
509 ev.xclient.data.l[2] = scr->managerWindow;
510 ev.xclient.data.l[3] = 0;
511 ev.xclient.data.l[4] = 0;
513 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
514 XSync(dpy, False);
516 return True;
518 #endif
521 *----------------------------------------------------------------------
522 * wScreenInit--
523 * Initializes the window manager for the given screen and
524 * allocates a WScreen descriptor for it. Many resources are allocated
525 * for the screen and the root window is setup appropriately.
527 * Returns:
528 * The WScreen descriptor for the screen.
530 * Side effects:
531 * Many resources are allocated and the IconSize property is
532 * set on the root window.
533 * The program can be aborted if some fatal error occurs.
535 * TODO: User specifiable visual.
536 *----------------------------------------------------------------------
538 WScreen *wScreenInit(int screen_number)
540 WScreen *scr;
541 XIconSize icon_size[1];
542 RContextAttributes rattr;
543 extern int wVisualID;
544 long event_mask;
545 XErrorHandler oldHandler;
546 int i;
548 scr = wmalloc(sizeof(WScreen));
549 memset(scr, 0, sizeof(WScreen));
551 scr->stacking_list = WMCreateTreeBag();
553 /* initialize globals */
554 scr->screen = screen_number;
555 scr->root_win = RootWindow(dpy, screen_number);
556 scr->depth = DefaultDepth(dpy, screen_number);
557 scr->colormap = DefaultColormap(dpy, screen_number);
559 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
560 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
562 wInitXinerama(scr);
564 scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
565 scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
567 for (i = 0; i < wXineramaHeads(scr); ++i) {
568 WMRect rect = wGetRectForHead(scr, i);
569 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
570 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
571 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
572 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
575 scr->fakeGroupLeaders = WMCreateArray(16);
577 #if 0
578 if (!aquireManagerSelection(scr)) {
579 wfree(scr);
581 return NULL;
583 #endif
584 CantManageScreen = 0;
585 oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
587 event_mask = EVENT_MASK;
589 if (wPreferences.disable_root_mouse) {
590 event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
593 XSelectInput(dpy, scr->root_win, event_mask);
595 #ifdef KEEP_XKB_LOCK_STATUS
596 /* Only GroupLock doesn't work correctly in my system since right-alt
597 * can change mode while holding it too - ]d
599 if (wXkbSupported) {
600 XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
602 #endif /* KEEP_XKB_LOCK_STATUS */
604 XSync(dpy, False);
605 XSetErrorHandler(oldHandler);
607 if (CantManageScreen) {
608 wfree(scr);
609 return NULL;
612 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
614 /* screen descriptor for raster graphic library */
615 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
616 rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
618 /* if the std colormap stuff works ok, this will be ignored */
619 rattr.colors_per_channel = wPreferences.cmap_size;
620 if (rattr.colors_per_channel < 2)
621 rattr.colors_per_channel = 2;
623 /* will only be accounted for in PseudoColor */
624 if (wPreferences.flags.create_stdcmap) {
625 rattr.standard_colormap_mode = RCreateStdColormap;
626 } else {
627 rattr.standard_colormap_mode = RUseStdColormap;
630 if (wVisualID >= 0) {
631 rattr.flags |= RC_VisualID;
632 rattr.visualid = wVisualID;
635 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
637 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
638 wwarning(RMessageForError(RErrorCode));
640 rattr.flags &= ~RC_StandardColormap;
641 rattr.standard_colormap_mode = RUseStdColormap;
643 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
646 if (!scr->rcontext) {
647 wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
648 wAbort(False);
649 } else {
650 char **formats;
651 int i = 0;
653 formats = RSupportedFileFormats();
654 if (formats) {
655 for (i = 0; formats[i] != NULL; i++) {
656 if (strcmp(formats[i], "TIFF") == 0) {
657 scr->flags.supports_tiff = 1;
658 break;
664 scr->w_win = scr->rcontext->drawable;
665 scr->w_visual = scr->rcontext->visual;
666 scr->w_depth = scr->rcontext->depth;
667 scr->w_colormap = scr->rcontext->cmap;
669 /* create screen descriptor for WINGs */
670 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
672 if (!scr->wmscreen) {
673 wfatal(_("could not initialize WINGs widget set"));
674 return NULL;
677 scr->black = WMBlackColor(scr->wmscreen);
678 scr->white = WMWhiteColor(scr->wmscreen);
679 scr->gray = WMGrayColor(scr->wmscreen);
680 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
682 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
683 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
684 scr->light_pixel = WMColorPixel(scr->gray);
685 scr->dark_pixel = WMColorPixel(scr->darkGray);
688 XColor xcol;
689 /* frame boder color */
690 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
691 scr->frame_border_pixel = xcol.pixel;
694 /* create GCs with default values */
695 allocGCs(scr);
697 /* for our window manager info notice board. Need to
698 * create before reading the defaults, because it will be used there.
700 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
702 /* read defaults for this screen */
703 wReadDefaults(scr, WDWindowMaker->dictionary);
705 createInternalWindows(scr);
707 #ifdef NETWM_HINTS
708 wNETWMInitStuff(scr);
709 #endif
711 /* create initial workspace */
712 wWorkspaceNew(scr);
714 /* create shared pixmaps */
715 createPixmaps(scr);
717 /* set icon sizes we can accept from clients */
718 icon_size[0].min_width = 8;
719 icon_size[0].min_height = 8;
720 icon_size[0].max_width = wPreferences.icon_size - 4;
721 icon_size[0].max_height = wPreferences.icon_size - 4;
722 icon_size[0].width_inc = 1;
723 icon_size[0].height_inc = 1;
724 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
726 /* setup WindowMaker protocols property in the root window */
727 PropSetWMakerProtocols(scr->root_win);
729 /* setup our noticeboard */
730 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
731 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
732 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
733 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
735 #ifdef BALLOON_TEXT
736 /* initialize balloon text stuff */
737 wBalloonInitialize(scr);
738 #endif
740 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
742 scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
743 if (!scr->tech_draw_font)
744 scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
746 scr->gview = WCreateGeometryView(scr->wmscreen);
747 WMRealizeWidget(scr->gview);
749 wScreenUpdateUsableArea(scr);
751 return scr;
754 void wScreenUpdateUsableArea(WScreen * scr)
757 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
758 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
759 * border.
762 int i;
763 unsigned long best_area = 0, tmp_area;
764 WArea area;
765 int dock_head = scr->xine_info.primary_head;
767 if (scr->dock) {
768 WMRect rect;
769 rect.pos.x = scr->dock->x_pos;
770 rect.pos.y = scr->dock->y_pos;
771 rect.size.width = wPreferences.icon_size;
772 rect.size.height = wPreferences.icon_size;
773 dock_head = wGetHeadForRect(scr, rect);
776 for (i = 0; i < wXineramaHeads(scr); ++i) {
777 WMRect rect = wGetRectForHead(scr, i);
778 scr->totalUsableArea[i].x1 = rect.pos.x;
779 scr->totalUsableArea[i].y1 = rect.pos.y;
780 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
781 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
783 if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
784 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
786 if (scr->dock->on_right_side) {
787 scr->totalUsableArea[i].x2 -= offset;
788 } else {
789 scr->totalUsableArea[i].x1 += offset;
792 #ifdef NETWM_HINTS
794 WArea area;
795 if (wNETWMGetUsableArea(scr, i, &area)) {
796 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
797 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
798 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
799 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
802 #endif
804 scr->usableArea[i] = scr->totalUsableArea[i];
806 #if 0
807 printf("usableArea[%d]: %d %d %d %d\n", i,
808 scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
809 #endif
811 if (wPreferences.no_window_over_icons) {
812 if (wPreferences.icon_yard & IY_VERT) {
813 if (wPreferences.icon_yard & IY_RIGHT) {
814 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
815 } else {
816 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
818 } else {
819 if (wPreferences.icon_yard & IY_TOP) {
820 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
821 } else {
822 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
827 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
828 scr->totalUsableArea[i].x1 = rect.pos.x;
829 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
832 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
833 scr->totalUsableArea[i].y1 = rect.pos.y;
834 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
837 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
838 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
840 if (tmp_area > best_area) {
841 best_area = tmp_area;
842 area = scr->totalUsableArea[i];
846 unsigned size = wPreferences.workspace_border_size;
847 unsigned position = wPreferences.workspace_border_position;
849 if (size > 0 && position != WB_NONE) {
850 if (position & WB_LEFTRIGHT) {
851 scr->totalUsableArea[i].x1 += size;
852 scr->totalUsableArea[i].x2 -= size;
854 if (position & WB_TOPBOTTOM) {
855 scr->totalUsableArea[i].y1 += size;
856 scr->totalUsableArea[i].y2 -= size;
862 #ifdef NETWM_HINTS
863 wNETWMUpdateWorkarea(scr, area);
864 #endif
866 if (wPreferences.auto_arrange_icons) {
867 wArrangeIcons(scr, True);
871 #if 0
872 void wScreenUpdateUsableArea(WScreen * scr)
874 scr->totalUsableArea = scr->usableArea;
876 if (scr->dock && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
878 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
880 if (scr->dock->on_right_side) {
881 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, scr->scr_width - offset);
882 } else {
883 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, offset);
887 if (wPreferences.no_window_over_icons) {
888 if (wPreferences.icon_yard & IY_VERT) {
890 if (!(wPreferences.icon_yard & IY_RIGHT)) {
891 scr->totalUsableArea.x1 += wPreferences.icon_size;
892 } else {
893 scr->totalUsableArea.x2 -= wPreferences.icon_size;
895 } else {
897 if (wPreferences.icon_yard & IY_TOP) {
898 scr->totalUsableArea.y1 += wPreferences.icon_size;
899 } else {
900 scr->totalUsableArea.y2 -= wPreferences.icon_size;
904 #ifdef NETWM_HINTS
906 WArea area;
907 if (wNETWMGetUsableArea(scr, &area)) {
908 scr->totalUsableArea.x1 = WMAX(scr->totalUsableArea.x1, area.x1);
909 scr->totalUsableArea.y1 = WMAX(scr->totalUsableArea.y1, area.y1);
910 scr->totalUsableArea.x2 = WMIN(scr->totalUsableArea.x2, area.x2);
911 scr->totalUsableArea.y2 = WMIN(scr->totalUsableArea.y2, area.y2);
914 #endif
916 if (scr->totalUsableArea.x2 - scr->totalUsableArea.x1 < scr->scr_width / 2) {
917 scr->totalUsableArea.x2 = scr->usableArea.x2;
918 scr->totalUsableArea.x1 = scr->usableArea.x1;
920 if (scr->totalUsableArea.y2 - scr->totalUsableArea.y1 < scr->scr_height / 2) {
921 scr->totalUsableArea.y2 = scr->usableArea.y2;
922 scr->totalUsableArea.y1 = scr->usableArea.y1;
924 #ifdef NETWM_HINTS
925 wNETWMUpdateWorkarea(scr);
926 #endif
929 unsigned size = wPreferences.workspace_border_size;
930 unsigned position = wPreferences.workspace_border_position;
932 if (size > 0 && position != WB_NONE) {
933 if (position & WB_LEFTRIGHT) {
934 scr->totalUsableArea.x1 += size;
935 scr->totalUsableArea.x2 -= size;
937 if (position & WB_TOPBOTTOM) {
938 scr->totalUsableArea.y1 += size;
939 scr->totalUsableArea.y2 -= size;
944 if (wPreferences.auto_arrange_icons) {
945 wArrangeIcons(scr, True);
948 #endif
950 void wScreenRestoreState(WScreen * scr)
952 WMPropList *state;
953 char *path;
955 OpenRootMenu(scr, -10000, -10000, False);
956 wMenuUnmap(scr->root_menu);
958 make_keys();
960 if (wScreenCount == 1) {
961 path = wdefaultspathfordomain("WMState");
962 } else {
963 char buf[16];
964 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
965 path = wdefaultspathfordomain(buf);
967 scr->session_state = WMReadPropListFromFile(path);
968 wfree(path);
969 if (!scr->session_state && wScreenCount > 1) {
970 path = wdefaultspathfordomain("WMState");
971 scr->session_state = WMReadPropListFromFile(path);
972 wfree(path);
975 if (!scr->session_state) {
976 scr->session_state = WMCreatePLDictionary(NULL, NULL);
979 if (!wPreferences.flags.nodock) {
980 state = WMGetFromPLDictionary(scr->session_state, dDock);
981 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
984 if (!wPreferences.flags.noclip) {
985 state = WMGetFromPLDictionary(scr->session_state, dClip);
986 scr->clip_icon = wClipRestoreState(scr, state);
989 wWorkspaceRestoreState(scr);
991 wScreenUpdateUsableArea(scr);
994 void wScreenSaveState(WScreen * scr)
996 WWindow *wwin;
997 char *str;
998 WMPropList *old_state, *foo;
1000 make_keys();
1002 /* save state of windows */
1003 wwin = scr->focused_window;
1004 while (wwin) {
1005 wWindowSaveState(wwin);
1006 wwin = wwin->prev;
1009 if (wPreferences.flags.noupdates)
1010 return;
1012 old_state = scr->session_state;
1013 scr->session_state = WMCreatePLDictionary(NULL, NULL);
1015 WMPLSetCaseSensitive(True);
1017 /* save dock state to file */
1018 if (!wPreferences.flags.nodock) {
1019 wDockSaveState(scr, old_state);
1020 } else {
1021 if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
1022 WMPutInPLDictionary(scr->session_state, dDock, foo);
1025 if (!wPreferences.flags.noclip) {
1026 wClipSaveState(scr);
1027 } else {
1028 if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
1029 WMPutInPLDictionary(scr->session_state, dClip, foo);
1033 wWorkspaceSaveState(scr, old_state);
1035 if (wPreferences.save_session_on_exit) {
1036 wSessionSaveState(scr);
1037 } else {
1038 if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
1039 WMPutInPLDictionary(scr->session_state, dApplications, foo);
1041 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
1042 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
1046 /* clean up */
1047 WMPLSetCaseSensitive(False);
1049 wMenuSaveState(scr);
1051 if (wScreenCount == 1) {
1052 str = wdefaultspathfordomain("WMState");
1053 } else {
1054 char buf[16];
1055 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
1056 str = wdefaultspathfordomain(buf);
1058 if (!WMWritePropListToFile(scr->session_state, str, True)) {
1059 wsyserror(_("could not save session state in %s"), str);
1061 wfree(str);
1062 WMReleasePropList(old_state);
1065 int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
1067 int moved = 0;
1068 int tol_w, tol_h;
1070 * With respect to the head that contains most of the window.
1072 int sx1, sy1, sx2, sy2;
1074 WMRect rect;
1075 int head, flags;
1077 rect.pos.x = *x;
1078 rect.pos.y = *y;
1079 rect.size.width = width;
1080 rect.size.height = height;
1082 head = wGetRectPlacementInfo(scr, rect, &flags);
1083 rect = wGetRectForHead(scr, head);
1085 sx1 = rect.pos.x;
1086 sy1 = rect.pos.y;
1087 sx2 = sx1 + rect.size.width;
1088 sy2 = sy1 + rect.size.height;
1090 #if 0 /* NOTE: gives funky group movement */
1091 if (flags & XFLAG_MULTIPLE) {
1093 * since we span multiple heads, pull window totaly inside
1095 if (*x < sx1)
1096 *x = sx1, moved = 1;
1097 else if (*x + width > sx2)
1098 *x = sx2 - width, moved = 1;
1100 if (*y < sy1)
1101 *y = sy1, moved = 1;
1102 else if (*y + height > sy2)
1103 *y = sy2 - height, moved = 1;
1105 return moved;
1107 #endif
1109 if (width > 20)
1110 tol_w = width / 2;
1111 else
1112 tol_w = 20;
1114 if (height > 20)
1115 tol_h = height / 2;
1116 else
1117 tol_h = 20;
1119 if (*x + width < sx1 + 10)
1120 *x = sx1 - tol_w, moved = 1;
1121 else if (*x >= sx2 - 10)
1122 *x = sx2 - tol_w - 1, moved = 1;
1124 if (*y < sy1 - height + 10)
1125 *y = sy1 - tol_h, moved = 1;
1126 else if (*y >= sy2 - 10)
1127 *y = sy2 - tol_h - 1, moved = 1;
1129 return moved;
1132 int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
1134 int moved = 0;
1135 int sx1, sy1, sx2, sy2;
1136 WMRect rect;
1137 int head;
1139 rect.pos.x = *x;
1140 rect.pos.y = *y;
1141 rect.size.width = width;
1142 rect.size.height = height;
1144 head = wGetHeadForRect(scr, rect);
1145 rect = wGetRectForHead(scr, head);
1147 sx1 = rect.pos.x;
1148 sy1 = rect.pos.y;
1149 sx2 = sx1 + rect.size.width;
1150 sy2 = sy1 + rect.size.height;
1152 if (*x < sx1)
1153 *x = sx1, moved = 1;
1154 else if (*x + width > sx2)
1155 *x = sx2 - width, moved = 1;
1157 if (*y < sy1)
1158 *y = sy1, moved = 1;
1159 else if (*y + height > sy2)
1160 *y = sy2 - height, moved = 1;
1162 return moved;