Address some sparse warnings
[wmaker-crm.git] / src / screen.c
blob1a119c25204656a6cde3998be74294bc0607a092
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 #include "wmspec.h"
58 #include "xinerama.h"
60 #include <WINGs/WUtil.h>
62 #include "defaults.h"
64 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
65 |SubstructureNotifyMask|PointerMotionMask \
66 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
67 |KeyPressMask|KeyReleaseMask)
69 /**** Global variables ****/
70 extern Cursor wCursor[WCUR_LAST];
71 extern WPreferences wPreferences;
72 extern Atom _XA_WINDOWMAKER_STATE;
73 extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
75 extern int wScreenCount;
77 #ifdef KEEP_XKB_LOCK_STATUS
78 extern int wXkbSupported;
79 #endif
81 extern WDDomain *WDWindowMaker;
83 /**** Local ****/
84 #define STIPPLE_WIDTH 2
85 #define STIPPLE_HEIGHT 2
86 static char STIPPLE_DATA[] = { 0x02, 0x01 };
88 static int CantManageScreen = 0;
90 static WMPropList *dApplications = NULL;
91 static WMPropList *dWorkspace;
92 static WMPropList *dDock;
93 static WMPropList *dClip;
95 static void make_keys(void)
97 if (dApplications != NULL)
98 return;
100 dApplications = WMCreatePLString("Applications");
101 dWorkspace = WMCreatePLString("Workspace");
102 dDock = WMCreatePLString("Dock");
103 dClip = WMCreatePLString("Clip");
107 *----------------------------------------------------------------------
108 * alreadyRunningError--
109 * X error handler used to catch errors when trying to do
110 * XSelectInput() on the root window. These errors probably mean that
111 * there already is some other window manager running.
113 * Returns:
114 * Nothing, unless something really evil happens...
116 * Side effects:
117 * CantManageScreen is set to 1;
118 *----------------------------------------------------------------------
120 static int alreadyRunningError(Display * dpy, XErrorEvent * error)
122 CantManageScreen = 1;
123 return -1;
127 *----------------------------------------------------------------------
128 * allocButtonPixmaps--
129 * Allocate pixmaps used on window operation buttons (those in the
130 * titlebar). The pixmaps are linked to the program. If XPM is supported
131 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
133 * Returns:
134 * Nothing
136 * Side effects:
137 * Allocates shared pixmaps for the screen. These pixmaps should
138 * not be freed by anybody.
139 *----------------------------------------------------------------------
141 static void allocButtonPixmaps(WScreen * scr)
143 WPixmap *pix;
145 /* create predefined pixmaps */
146 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
147 if (pix)
148 pix->shared = 1;
149 scr->b_pixmaps[WBUT_CLOSE] = pix;
151 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
152 if (pix)
153 pix->shared = 1;
154 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
156 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
157 if (pix)
158 pix->shared = 1;
159 scr->b_pixmaps[WBUT_ICONIFY] = pix;
160 #ifdef XKB_BUTTON_HINT
161 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
162 if (pix)
163 pix->shared = 1;
164 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
165 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
166 if (pix)
167 pix->shared = 1;
168 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
169 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
170 if (pix)
171 pix->shared = 1;
172 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
173 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
174 if (pix)
175 pix->shared = 1;
176 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
177 #endif
179 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
180 if (pix)
181 pix->shared = 1;
182 scr->b_pixmaps[WBUT_KILL] = pix;
185 static void draw_dot(WScreen * scr, Drawable d, int x, int y, GC gc)
187 XSetForeground(dpy, gc, scr->black_pixel);
188 XDrawLine(dpy, d, gc, x, y, x + 1, y);
189 XDrawPoint(dpy, d, gc, x, y + 1);
190 XSetForeground(dpy, gc, scr->white_pixel);
191 XDrawLine(dpy, d, gc, x + 2, y, x + 2, y + 1);
192 XDrawPoint(dpy, d, gc, x + 1, y + 1);
195 static WPixmap *make3Dots(WScreen * scr)
197 WPixmap *wpix;
198 GC gc2, gc;
199 XGCValues gcv;
200 Pixmap pix, mask;
202 gc = scr->copy_gc;
203 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
204 XSetForeground(dpy, gc, scr->black_pixel);
205 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
206 XSetForeground(dpy, gc, scr->white_pixel);
207 draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
208 draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
209 draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
211 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
212 gcv.foreground = 0;
213 gcv.graphics_exposures = False;
214 gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
215 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
216 XSetForeground(dpy, gc2, 1);
217 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
218 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
219 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
221 XFreeGC(dpy, gc2);
223 wpix = wPixmapCreate(scr, pix, mask);
224 wpix->shared = 1;
226 return wpix;
229 static void allocGCs(WScreen * scr)
231 XGCValues gcv;
232 XColor color;
233 int gcm;
235 scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
237 gcv.stipple = scr->stipple_bitmap;
238 gcv.foreground = scr->white_pixel;
239 gcv.fill_style = FillStippled;
240 gcv.graphics_exposures = False;
241 gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
242 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
244 /* selected icon border GCs */
245 gcv.function = GXcopy;
246 gcv.foreground = scr->white_pixel;
247 gcv.background = scr->black_pixel;
248 gcv.line_width = 1;
249 gcv.line_style = LineDoubleDash;
250 gcv.fill_style = FillSolid;
251 gcv.dash_offset = 0;
252 gcv.dashes = 4;
253 gcv.graphics_exposures = False;
255 gcm = GCFunction | GCGraphicsExposures;
256 gcm |= GCForeground | GCBackground;
257 gcm |= GCLineWidth | GCLineStyle;
258 gcm |= GCFillStyle;
259 gcm |= GCDashOffset | GCDashList;
261 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
263 scr->menu_title_color[0] = WMRetainColor(scr->white);
265 /* don't retain scr->black here because we may alter its alpha */
266 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
267 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
269 /* frame GC */
270 wGetColor(scr, DEF_FRAME_COLOR, &color);
271 gcv.function = GXxor;
272 /* this will raise the probability of the XORed color being different
273 * of the original color in PseudoColor when not all color cells are
274 * initialized */
275 if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
276 gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
277 else
278 gcv.plane_mask = AllPlanes;
279 gcv.foreground = color.pixel;
280 if (gcv.foreground == 0)
281 gcv.foreground = 1;
282 gcv.line_width = DEF_FRAME_THICKNESS;
283 gcv.subwindow_mode = IncludeInferiors;
284 gcv.graphics_exposures = False;
285 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
286 | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
288 /* line GC */
289 gcv.foreground = color.pixel;
291 if (gcv.foreground == 0)
292 /* XOR:ing with a zero is not going to be of much use, so
293 in that case, we somewhat arbitrarily xor with 17 instead. */
294 gcv.foreground = 17;
296 gcv.function = GXxor;
297 gcv.subwindow_mode = IncludeInferiors;
298 gcv.line_width = 1;
299 gcv.cap_style = CapRound;
300 gcv.graphics_exposures = False;
301 gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
302 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
304 scr->line_pixel = gcv.foreground;
306 /* copy GC */
307 gcv.foreground = scr->white_pixel;
308 gcv.background = scr->black_pixel;
309 gcv.graphics_exposures = False;
310 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
312 /* misc drawing GC */
313 gcv.graphics_exposures = False;
314 gcm = GCGraphicsExposures;
315 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
317 assert(scr->stipple_bitmap != None);
319 /* mono GC */
320 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
323 static void createPixmaps(WScreen * scr)
325 WPixmap *pix;
326 RImage *image;
328 /* load pixmaps */
329 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_RADIO_INDICATOR_XBM_DATA,
330 (char *)MENU_RADIO_INDICATOR_XBM_DATA,
331 MENU_RADIO_INDICATOR_XBM_SIZE,
332 MENU_RADIO_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
333 if (pix != NULL)
334 pix->shared = 1;
335 scr->menu_radio_indicator = pix;
337 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
338 (char *)MENU_CHECK_INDICATOR_XBM_DATA,
339 MENU_CHECK_INDICATOR_XBM_SIZE,
340 MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
341 if (pix != NULL)
342 pix->shared = 1;
343 scr->menu_check_indicator = pix;
345 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
346 (char *)MENU_MINI_INDICATOR_XBM_DATA,
347 MENU_MINI_INDICATOR_XBM_SIZE,
348 MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
349 if (pix != NULL)
350 pix->shared = 1;
351 scr->menu_mini_indicator = pix;
353 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
354 (char *)MENU_HIDE_INDICATOR_XBM_DATA,
355 MENU_HIDE_INDICATOR_XBM_SIZE,
356 MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
357 if (pix != NULL)
358 pix->shared = 1;
359 scr->menu_hide_indicator = pix;
361 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
362 (char *)MENU_SHADE_INDICATOR_XBM_DATA,
363 MENU_SHADE_INDICATOR_XBM_SIZE,
364 MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
365 if (pix != NULL)
366 pix->shared = 1;
367 scr->menu_shade_indicator = pix;
369 image = wDefaultGetImage(scr, "Logo", "WMPanel");
371 if (!image) {
372 wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
373 } else {
374 WMSetApplicationIconImage(scr->wmscreen, image);
375 RReleaseImage(image);
378 scr->dock_dots = make3Dots(scr);
380 /* titlebar button pixmaps */
381 allocButtonPixmaps(scr);
385 *----------------------------------------------------------------------
386 * createInternalWindows--
387 * Creates some windows used internally by the program. One to
388 * receive input focus when no other window can get it and another
389 * to display window geometry information during window resize/move.
391 * Returns:
392 * Nothing
394 * Side effects:
395 * Windows are created and some colors are allocated for the
396 * window background.
397 *----------------------------------------------------------------------
399 static void createInternalWindows(WScreen * scr)
401 int vmask;
402 XSetWindowAttributes attribs;
404 /* InputOnly window to get the focus when no other window can get it */
405 vmask = CWEventMask | CWOverrideRedirect;
406 attribs.event_mask = KeyPressMask | FocusChangeMask;
407 attribs.override_redirect = True;
408 scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
409 InputOnly, CopyFromParent, vmask, &attribs);
410 XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
411 XMapWindow(dpy, scr->no_focus_win);
413 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
415 /* shadow window for dock buttons */
416 vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
417 attribs.border_pixel = scr->black_pixel;
418 attribs.save_under = True;
419 attribs.override_redirect = True;
420 attribs.background_pixmap = None;
421 attribs.background_pixel = scr->white_pixel;
422 attribs.cursor = wCursor[WCUR_DEFAULT];
423 vmask |= CWColormap;
424 attribs.colormap = scr->w_colormap;
425 scr->dock_shadow =
426 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
427 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
429 /* workspace name balloon for clip */
430 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
431 attribs.save_under = True;
432 attribs.override_redirect = True;
433 attribs.colormap = scr->w_colormap;
434 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
435 attribs.border_pixel = 0; /* do not care */
436 scr->clip_balloon =
437 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
438 CopyFromParent, scr->w_visual, vmask, &attribs);
440 /* workspace name */
441 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
442 attribs.save_under = True;
443 attribs.override_redirect = True;
444 attribs.colormap = scr->w_colormap;
445 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
446 attribs.border_pixel = 0; /* do not care */
447 scr->workspace_name =
448 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
449 CopyFromParent, scr->w_visual, vmask, &attribs);
452 * If the window is clicked without having ButtonPress selected, the
453 * resulting event will have event.xbutton.window == root.
455 XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
458 #if 0
459 static Bool aquireManagerSelection(WScreen * scr)
461 char buffer[32];
462 XEvent ev;
463 Time timestamp;
465 snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
466 scr->managerAtom = XInternAtom(dpy, buffer, False);
468 /* for race-conditions... */
469 XGrabServer(dpy);
471 /* if there is another manager running, don't try to replace it
472 * (for now, at least) */
473 if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
474 XUngrabServer(dpy);
475 return False;
478 /* become the manager for this screen */
480 scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1, 0, 0, 0);
482 XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
483 /* get a timestamp */
484 XChangeProperty(dpy, scr->managerWindow, scr->managerAtom, XA_INTEGER, 32, PropModeAppend, NULL, 0);
485 while (1) {
486 XWindowEvent(dpy, scr->managerWindow, &ev);
487 if (ev.type == PropertyNotify) {
488 timestamp = ev.xproperty.time;
489 break;
492 XSelectInput(dpy, scr->managerWindow, NoEvents);
493 XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
495 XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
497 XUngrabServer(dpy);
499 /* announce our arrival */
501 ev.xclient.type = ClientMessage;
502 ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
503 ev.xclient.destination = scr->root_win;
504 ev.xclient.format = 32;
505 ev.xclient.data.l[0] = timestamp;
506 ev.xclient.data.l[1] = scr->managerAtom;
507 ev.xclient.data.l[2] = scr->managerWindow;
508 ev.xclient.data.l[3] = 0;
509 ev.xclient.data.l[4] = 0;
511 XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
512 XSync(dpy, False);
514 return True;
516 #endif
519 *----------------------------------------------------------------------
520 * wScreenInit--
521 * Initializes the window manager for the given screen and
522 * allocates a WScreen descriptor for it. Many resources are allocated
523 * for the screen and the root window is setup appropriately.
525 * Returns:
526 * The WScreen descriptor for the screen.
528 * Side effects:
529 * Many resources are allocated and the IconSize property is
530 * set on the root window.
531 * The program can be aborted if some fatal error occurs.
533 * TODO: User specifiable visual.
534 *----------------------------------------------------------------------
536 WScreen *wScreenInit(int screen_number)
538 WScreen *scr;
539 XIconSize icon_size[1];
540 RContextAttributes rattr;
541 long event_mask;
542 XErrorHandler oldHandler;
543 int i;
545 scr = wmalloc(sizeof(WScreen));
546 memset(scr, 0, sizeof(WScreen));
548 scr->stacking_list = WMCreateTreeBag();
550 /* initialize globals */
551 scr->screen = screen_number;
552 scr->root_win = RootWindow(dpy, screen_number);
553 scr->depth = DefaultDepth(dpy, screen_number);
554 scr->colormap = DefaultColormap(dpy, screen_number);
556 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
557 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
559 wInitXinerama(scr);
561 scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
562 scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
564 for (i = 0; i < wXineramaHeads(scr); ++i) {
565 WMRect rect = wGetRectForHead(scr, i);
566 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
567 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
568 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
569 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
572 scr->fakeGroupLeaders = WMCreateArray(16);
574 #if 0
575 if (!aquireManagerSelection(scr)) {
576 wfree(scr);
578 return NULL;
580 #endif
581 CantManageScreen = 0;
582 oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
584 event_mask = EVENT_MASK;
586 if (wPreferences.disable_root_mouse) {
587 event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
590 XSelectInput(dpy, scr->root_win, event_mask);
592 #ifdef KEEP_XKB_LOCK_STATUS
593 /* Only GroupLock doesn't work correctly in my system since right-alt
594 * can change mode while holding it too - ]d
596 if (wXkbSupported) {
597 XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
599 #endif /* KEEP_XKB_LOCK_STATUS */
601 XSync(dpy, False);
602 XSetErrorHandler(oldHandler);
604 if (CantManageScreen) {
605 wfree(scr);
606 return NULL;
609 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
611 /* screen descriptor for raster graphic library */
612 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
613 rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
615 /* if the std colormap stuff works ok, this will be ignored */
616 rattr.colors_per_channel = wPreferences.cmap_size;
617 if (rattr.colors_per_channel < 2)
618 rattr.colors_per_channel = 2;
620 /* will only be accounted for in PseudoColor */
621 if (wPreferences.flags.create_stdcmap) {
622 rattr.standard_colormap_mode = RCreateStdColormap;
623 } else {
624 rattr.standard_colormap_mode = RUseStdColormap;
627 if (getWVisualID(screen_number) >= 0) {
628 rattr.flags |= RC_VisualID;
629 rattr.visualid = getWVisualID(screen_number);
632 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
634 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
635 wwarning(RMessageForError(RErrorCode));
637 rattr.flags &= ~RC_StandardColormap;
638 rattr.standard_colormap_mode = RUseStdColormap;
640 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
643 if (!scr->rcontext) {
644 wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
645 wAbort(False);
646 } else {
647 char **formats;
648 int i = 0;
650 formats = RSupportedFileFormats();
651 if (formats) {
652 for (i = 0; formats[i] != NULL; i++) {
653 if (strcmp(formats[i], "TIFF") == 0) {
654 scr->flags.supports_tiff = 1;
655 break;
661 scr->w_win = scr->rcontext->drawable;
662 scr->w_visual = scr->rcontext->visual;
663 scr->w_depth = scr->rcontext->depth;
664 scr->w_colormap = scr->rcontext->cmap;
666 /* create screen descriptor for WINGs */
667 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
669 if (!scr->wmscreen) {
670 wfatal(_("could not initialize WINGs widget set"));
671 return NULL;
674 scr->black = WMBlackColor(scr->wmscreen);
675 scr->white = WMWhiteColor(scr->wmscreen);
676 scr->gray = WMGrayColor(scr->wmscreen);
677 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
679 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
680 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
681 scr->light_pixel = WMColorPixel(scr->gray);
682 scr->dark_pixel = WMColorPixel(scr->darkGray);
685 XColor xcol;
686 /* frame boder color */
687 wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
688 scr->frame_border_pixel = xcol.pixel;
691 /* create GCs with default values */
692 allocGCs(scr);
694 /* for our window manager info notice board. Need to
695 * create before reading the defaults, because it will be used there.
697 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
699 /* read defaults for this screen */
700 wReadDefaults(scr, WDWindowMaker->dictionary);
702 createInternalWindows(scr);
704 wNETWMInitStuff(scr);
706 /* create initial workspace */
707 wWorkspaceNew(scr);
709 /* create shared pixmaps */
710 createPixmaps(scr);
712 /* set icon sizes we can accept from clients */
713 icon_size[0].min_width = 8;
714 icon_size[0].min_height = 8;
715 icon_size[0].max_width = wPreferences.icon_size - 4;
716 icon_size[0].max_height = wPreferences.icon_size - 4;
717 icon_size[0].width_inc = 1;
718 icon_size[0].height_inc = 1;
719 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
721 /* setup WindowMaker protocols property in the root window */
722 PropSetWMakerProtocols(scr->root_win);
724 /* setup our noticeboard */
725 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
726 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
727 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
728 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
730 #ifdef BALLOON_TEXT
731 /* initialize balloon text stuff */
732 wBalloonInitialize(scr);
733 #endif
735 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
737 scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
738 if (!scr->tech_draw_font)
739 scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
741 scr->gview = WCreateGeometryView(scr->wmscreen);
742 WMRealizeWidget(scr->gview);
744 wScreenUpdateUsableArea(scr);
746 return scr;
749 void wScreenUpdateUsableArea(WScreen * scr)
752 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
753 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
754 * border.
757 int i;
758 unsigned long best_area = 0, tmp_area;
759 WArea area;
760 int dock_head = scr->xine_info.primary_head;
762 if (scr->dock) {
763 WMRect rect;
764 rect.pos.x = scr->dock->x_pos;
765 rect.pos.y = scr->dock->y_pos;
766 rect.size.width = wPreferences.icon_size;
767 rect.size.height = wPreferences.icon_size;
768 dock_head = wGetHeadForRect(scr, rect);
771 for (i = 0; i < wXineramaHeads(scr); ++i) {
772 WMRect rect = wGetRectForHead(scr, i);
773 scr->totalUsableArea[i].x1 = rect.pos.x;
774 scr->totalUsableArea[i].y1 = rect.pos.y;
775 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
776 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
778 if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
779 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
781 if (scr->dock->on_right_side) {
782 scr->totalUsableArea[i].x2 -= offset;
783 } else {
784 scr->totalUsableArea[i].x1 += offset;
789 WArea area;
790 if (wNETWMGetUsableArea(scr, i, &area)) {
791 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
792 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
793 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
794 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
798 scr->usableArea[i] = scr->totalUsableArea[i];
800 #if 0
801 printf("usableArea[%d]: %d %d %d %d\n", i,
802 scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
803 #endif
805 if (wPreferences.no_window_over_icons) {
806 if (wPreferences.icon_yard & IY_VERT) {
807 if (wPreferences.icon_yard & IY_RIGHT) {
808 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
809 } else {
810 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
812 } else {
813 if (wPreferences.icon_yard & IY_TOP) {
814 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
815 } else {
816 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
821 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
822 scr->totalUsableArea[i].x1 = rect.pos.x;
823 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
826 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
827 scr->totalUsableArea[i].y1 = rect.pos.y;
828 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
831 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
832 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
834 if (tmp_area > best_area) {
835 best_area = tmp_area;
836 area = scr->totalUsableArea[i];
840 unsigned size = wPreferences.workspace_border_size;
841 unsigned position = wPreferences.workspace_border_position;
843 if (size > 0 && position != WB_NONE) {
844 if (position & WB_LEFTRIGHT) {
845 scr->totalUsableArea[i].x1 += size;
846 scr->totalUsableArea[i].x2 -= size;
848 if (position & WB_TOPBOTTOM) {
849 scr->totalUsableArea[i].y1 += size;
850 scr->totalUsableArea[i].y2 -= size;
856 wNETWMUpdateWorkarea(scr, area);
858 if (wPreferences.auto_arrange_icons)
859 wArrangeIcons(scr, True);
862 void wScreenRestoreState(WScreen * scr)
864 WMPropList *state;
865 char *path;
867 OpenRootMenu(scr, -10000, -10000, False);
868 wMenuUnmap(scr->root_menu);
870 make_keys();
872 if (wScreenCount == 1) {
873 path = wdefaultspathfordomain("WMState");
874 } else {
875 char buf[16];
876 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
877 path = wdefaultspathfordomain(buf);
879 scr->session_state = WMReadPropListFromFile(path);
880 wfree(path);
881 if (!scr->session_state && wScreenCount > 1) {
882 path = wdefaultspathfordomain("WMState");
883 scr->session_state = WMReadPropListFromFile(path);
884 wfree(path);
887 if (!scr->session_state) {
888 scr->session_state = WMCreatePLDictionary(NULL, NULL);
891 if (!wPreferences.flags.nodock) {
892 state = WMGetFromPLDictionary(scr->session_state, dDock);
893 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
896 if (!wPreferences.flags.noclip) {
897 state = WMGetFromPLDictionary(scr->session_state, dClip);
898 scr->clip_icon = wClipRestoreState(scr, state);
901 wWorkspaceRestoreState(scr);
903 wScreenUpdateUsableArea(scr);
906 void wScreenSaveState(WScreen * scr)
908 WWindow *wwin;
909 char *str;
910 WMPropList *old_state, *foo;
912 make_keys();
914 /* save state of windows */
915 wwin = scr->focused_window;
916 while (wwin) {
917 wWindowSaveState(wwin);
918 wwin = wwin->prev;
921 if (wPreferences.flags.noupdates)
922 return;
924 old_state = scr->session_state;
925 scr->session_state = WMCreatePLDictionary(NULL, NULL);
927 WMPLSetCaseSensitive(True);
929 /* save dock state to file */
930 if (!wPreferences.flags.nodock) {
931 wDockSaveState(scr, old_state);
932 } else {
933 if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
934 WMPutInPLDictionary(scr->session_state, dDock, foo);
937 if (!wPreferences.flags.noclip) {
938 wClipSaveState(scr);
939 } else {
940 if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
941 WMPutInPLDictionary(scr->session_state, dClip, foo);
945 wWorkspaceSaveState(scr, old_state);
947 if (wPreferences.save_session_on_exit) {
948 wSessionSaveState(scr);
949 } else {
950 if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
951 WMPutInPLDictionary(scr->session_state, dApplications, foo);
953 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
954 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
958 /* clean up */
959 WMPLSetCaseSensitive(False);
961 wMenuSaveState(scr);
963 if (wScreenCount == 1) {
964 str = wdefaultspathfordomain("WMState");
965 } else {
966 char buf[16];
967 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
968 str = wdefaultspathfordomain(buf);
970 if (!WMWritePropListToFile(scr->session_state, str)) {
971 wsyserror(_("could not save session state in %s"), str);
973 wfree(str);
974 WMReleasePropList(old_state);
977 int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
979 int moved = 0;
980 int tol_w, tol_h;
982 * With respect to the head that contains most of the window.
984 int sx1, sy1, sx2, sy2;
986 WMRect rect;
987 int head, flags;
989 rect.pos.x = *x;
990 rect.pos.y = *y;
991 rect.size.width = width;
992 rect.size.height = height;
994 head = wGetRectPlacementInfo(scr, rect, &flags);
995 rect = wGetRectForHead(scr, head);
997 sx1 = rect.pos.x;
998 sy1 = rect.pos.y;
999 sx2 = sx1 + rect.size.width;
1000 sy2 = sy1 + rect.size.height;
1002 #if 0 /* NOTE: gives funky group movement */
1003 if (flags & XFLAG_MULTIPLE) {
1005 * since we span multiple heads, pull window totaly inside
1007 if (*x < sx1)
1008 *x = sx1, moved = 1;
1009 else if (*x + width > sx2)
1010 *x = sx2 - width, moved = 1;
1012 if (*y < sy1)
1013 *y = sy1, moved = 1;
1014 else if (*y + height > sy2)
1015 *y = sy2 - height, moved = 1;
1017 return moved;
1019 #endif
1021 if (width > 20)
1022 tol_w = width / 2;
1023 else
1024 tol_w = 20;
1026 if (height > 20)
1027 tol_h = height / 2;
1028 else
1029 tol_h = 20;
1031 if (*x + width < sx1 + 10)
1032 *x = sx1 - tol_w, moved = 1;
1033 else if (*x >= sx2 - 10)
1034 *x = sx2 - tol_w - 1, moved = 1;
1036 if (*y < sy1 - height + 10)
1037 *y = sy1 - tol_h, moved = 1;
1038 else if (*y >= sy2 - 10)
1039 *y = sy2 - tol_h - 1, moved = 1;
1041 return moved;
1044 int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
1046 int moved = 0;
1047 int sx1, sy1, sx2, sy2;
1048 WMRect rect;
1049 int head;
1051 rect.pos.x = *x;
1052 rect.pos.y = *y;
1053 rect.size.width = width;
1054 rect.size.height = height;
1056 head = wGetHeadForRect(scr, rect);
1057 rect = wGetRectForHead(scr, head);
1059 sx1 = rect.pos.x;
1060 sy1 = rect.pos.y;
1061 sx2 = sx1 + rect.size.width;
1062 sy2 = sy1 + rect.size.height;
1064 if (*x < sx1)
1065 *x = sx1, moved = 1;
1066 else if (*x + width > sx2)
1067 *x = sx2 - width, moved = 1;
1069 if (*y < sy1)
1070 *y = sy1, moved = 1;
1071 else if (*y + height > sy2)
1072 *y = sy2 - height, moved = 1;
1074 return moved;