wmaker: Replaced local 'extern' definition of wPreferences by proper header usage
[wmaker-crm.git] / src / screen.c
bloba5cb5fbfb14490d2889ede1e6690aea317ece739
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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "wconfig.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #include <X11/Xatom.h>
31 #ifdef SHAPE
32 #include <X11/extensions/shape.h>
33 #endif
34 #ifdef KEEP_XKB_LOCK_STATUS
35 #include <X11/XKBlib.h>
36 #endif /* KEEP_XKB_LOCK_STATUS */
37 #ifdef HAVE_XRANDR
38 #include <X11/extensions/Xrandr.h>
39 #endif
41 #include <wraster.h>
42 #include "WindowMaker.h"
43 #include "def_pixmaps.h"
44 #include "screen.h"
45 #include "texture.h"
46 #include "pixmap.h"
47 #include "menu.h"
48 #include "window.h"
49 #include "main.h"
50 #include "actions.h"
51 #include "properties.h"
52 #include "dock.h"
53 #include "resources.h"
54 #include "workspace.h"
55 #include "session.h"
56 #include "balloon.h"
57 #include "geomview.h"
58 #include "wmspec.h"
59 #include "rootmenu.h"
61 #include "xinerama.h"
63 #include <WINGs/WUtil.h>
65 #include "defaults.h"
67 #define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
68 |SubstructureNotifyMask|PointerMotionMask \
69 |SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
70 |KeyPressMask|KeyReleaseMask)
72 /**** Global variables ****/
73 extern Cursor wCursor[WCUR_LAST];
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 #ifdef HAVE_XRANDR
84 Bool has_randr;
85 int randr_event_base;
86 #endif
88 extern WDDomain *WDWindowMaker;
90 /**** Local ****/
91 #define STIPPLE_WIDTH 2
92 #define STIPPLE_HEIGHT 2
93 static char STIPPLE_DATA[] = { 0x02, 0x01 };
95 static int CantManageScreen = 0;
97 static WMPropList *dApplications = NULL;
98 static WMPropList *dWorkspace;
99 static WMPropList *dDock;
100 static WMPropList *dClip;
101 static WMPropList *dDrawers = NULL;
103 static void make_keys(void)
105 if (dApplications != NULL)
106 return;
108 dApplications = WMCreatePLString("Applications");
109 dWorkspace = WMCreatePLString("Workspace");
110 dDock = WMCreatePLString("Dock");
111 dClip = WMCreatePLString("Clip");
112 dDrawers = WMCreatePLString("Drawers");
116 *----------------------------------------------------------------------
117 * alreadyRunningError--
118 * X error handler used to catch errors when trying to do
119 * XSelectInput() on the root window. These errors probably mean that
120 * there already is some other window manager running.
122 * Returns:
123 * Nothing, unless something really evil happens...
125 * Side effects:
126 * CantManageScreen is set to 1;
127 *----------------------------------------------------------------------
129 static int alreadyRunningError(Display * dpy, XErrorEvent * error)
131 CantManageScreen = 1;
132 return -1;
136 *----------------------------------------------------------------------
137 * allocButtonPixmaps--
138 * Allocate pixmaps used on window operation buttons (those in the
139 * titlebar). The pixmaps are linked to the program. If XPM is supported
140 * XPM pixmaps are used otherwise, equivalent bitmaps are used.
142 * Returns:
143 * Nothing
145 * Side effects:
146 * Allocates shared pixmaps for the screen. These pixmaps should
147 * not be freed by anybody.
148 *----------------------------------------------------------------------
150 static void allocButtonPixmaps(WScreen * scr)
152 WPixmap *pix;
154 /* create predefined pixmaps */
155 if (wPreferences.new_style == TS_NEXT) {
156 pix = wPixmapCreateFromXPMData(scr, NEXT_CLOSE_XPM);
157 } else {
158 pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
160 if (pix)
161 pix->shared = 1;
162 scr->b_pixmaps[WBUT_CLOSE] = pix;
164 if (wPreferences.new_style == TS_NEXT) {
165 pix = wPixmapCreateFromXPMData(scr, NEXT_BROKEN_CLOSE_XPM);
166 } else {
167 pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
169 if (pix)
170 pix->shared = 1;
171 scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
173 if (wPreferences.new_style == TS_NEXT) {
174 pix = wPixmapCreateFromXPMData(scr, NEXT_ICONIFY_XPM);
175 } else {
176 pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
178 if (pix)
179 pix->shared = 1;
180 scr->b_pixmaps[WBUT_ICONIFY] = pix;
181 #ifdef XKB_BUTTON_HINT
182 if (wPreferences.new_style == TS_NEXT) {
183 pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP1_XPM);
184 } else {
185 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
187 if (pix)
188 pix->shared = 1;
189 scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
190 if (wPreferences.new_style == TS_NEXT) {
191 pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP2_XPM);
192 } else {
193 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
195 if (pix)
196 pix->shared = 1;
197 scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
198 if (wPreferences.new_style == TS_NEXT) {
199 pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP3_XPM);
200 } else {
201 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
203 if (pix)
204 pix->shared = 1;
205 scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
206 if (wPreferences.new_style == TS_NEXT) {
207 pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP4_XPM);
208 } else {
209 pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
211 if (pix)
212 pix->shared = 1;
213 scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
214 #endif
216 if (wPreferences.new_style == TS_NEXT) {
217 pix = wPixmapCreateFromXPMData(scr, NEXT_KILL_XPM);
218 } else {
219 pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
221 if (pix)
222 pix->shared = 1;
223 scr->b_pixmaps[WBUT_KILL] = pix;
226 static void draw_dot(WScreen * scr, Drawable d, int x, int y, GC gc)
228 XSetForeground(dpy, gc, scr->black_pixel);
229 XDrawLine(dpy, d, gc, x, y, x + 1, y);
230 XDrawPoint(dpy, d, gc, x, y + 1);
231 XSetForeground(dpy, gc, scr->white_pixel);
232 XDrawLine(dpy, d, gc, x + 2, y, x + 2, y + 1);
233 XDrawPoint(dpy, d, gc, x + 1, y + 1);
236 static WPixmap *make3Dots(WScreen * scr)
238 WPixmap *wpix;
239 GC gc2, gc;
240 XGCValues gcv;
241 Pixmap pix, mask;
243 gc = scr->copy_gc;
244 pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
245 XSetForeground(dpy, gc, scr->black_pixel);
246 XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
247 XSetForeground(dpy, gc, scr->white_pixel);
248 draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
249 draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
250 draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
252 mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
253 gcv.foreground = 0;
254 gcv.graphics_exposures = False;
255 gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
256 XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
257 XSetForeground(dpy, gc2, 1);
258 XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
259 XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
260 XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
262 XFreeGC(dpy, gc2);
264 wpix = wPixmapCreate(scr, pix, mask);
265 wpix->shared = 1;
267 return wpix;
270 static void allocGCs(WScreen * scr)
272 XGCValues gcv;
273 XColor color;
274 int gcm;
276 scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
278 gcv.stipple = scr->stipple_bitmap;
279 gcv.foreground = scr->white_pixel;
280 gcv.fill_style = FillStippled;
281 gcv.graphics_exposures = False;
282 gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
283 scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
285 /* selected icon border GCs */
286 gcv.function = GXcopy;
287 gcv.foreground = scr->white_pixel;
288 gcv.background = scr->black_pixel;
289 gcv.line_width = 1;
290 gcv.line_style = LineDoubleDash;
291 gcv.fill_style = FillSolid;
292 gcv.dash_offset = 0;
293 gcv.dashes = 4;
294 gcv.graphics_exposures = False;
296 gcm = GCFunction | GCGraphicsExposures;
297 gcm |= GCForeground | GCBackground;
298 gcm |= GCLineWidth | GCLineStyle;
299 gcm |= GCFillStyle;
300 gcm |= GCDashOffset | GCDashList;
302 scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
304 scr->menu_title_color[0] = WMRetainColor(scr->white);
306 /* don't retain scr->black here because we may alter its alpha */
307 scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
308 scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
310 /* frame GC */
311 wGetColor(scr, DEF_FRAME_COLOR, &color);
312 gcv.function = GXxor;
313 /* this will raise the probability of the XORed color being different
314 * of the original color in PseudoColor when not all color cells are
315 * initialized */
316 if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
317 gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
318 else
319 gcv.plane_mask = AllPlanes;
320 gcv.foreground = color.pixel;
321 if (gcv.foreground == 0)
322 gcv.foreground = 1;
323 gcv.line_width = DEF_FRAME_THICKNESS;
324 gcv.subwindow_mode = IncludeInferiors;
325 gcv.graphics_exposures = False;
326 scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
327 | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
329 /* line GC */
330 gcv.foreground = color.pixel;
332 if (gcv.foreground == 0)
333 /* XOR:ing with a zero is not going to be of much use, so
334 in that case, we somewhat arbitrarily xor with 17 instead. */
335 gcv.foreground = 17;
337 gcv.function = GXxor;
338 gcv.subwindow_mode = IncludeInferiors;
339 gcv.line_width = 1;
340 gcv.cap_style = CapRound;
341 gcv.graphics_exposures = False;
342 gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
343 scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
345 scr->line_pixel = gcv.foreground;
347 /* copy GC */
348 gcv.foreground = scr->white_pixel;
349 gcv.background = scr->black_pixel;
350 gcv.graphics_exposures = False;
351 scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
353 /* misc drawing GC */
354 gcv.graphics_exposures = False;
355 gcm = GCGraphicsExposures;
356 scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
358 assert(scr->stipple_bitmap != None);
360 /* mono GC */
361 scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
364 static void createPixmaps(WScreen * scr)
366 WPixmap *pix;
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, scr->black_pixel, scr->white_pixel);
373 if (pix != NULL)
374 pix->shared = 1;
375 scr->menu_radio_indicator = pix;
377 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
378 (char *)MENU_CHECK_INDICATOR_XBM_DATA,
379 MENU_CHECK_INDICATOR_XBM_SIZE,
380 MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
381 if (pix != NULL)
382 pix->shared = 1;
383 scr->menu_check_indicator = pix;
385 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
386 (char *)MENU_MINI_INDICATOR_XBM_DATA,
387 MENU_MINI_INDICATOR_XBM_SIZE,
388 MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
389 if (pix != NULL)
390 pix->shared = 1;
391 scr->menu_mini_indicator = pix;
393 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
394 (char *)MENU_HIDE_INDICATOR_XBM_DATA,
395 MENU_HIDE_INDICATOR_XBM_SIZE,
396 MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
397 if (pix != NULL)
398 pix->shared = 1;
399 scr->menu_hide_indicator = pix;
401 pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
402 (char *)MENU_SHADE_INDICATOR_XBM_DATA,
403 MENU_SHADE_INDICATOR_XBM_SIZE,
404 MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
405 if (pix != NULL)
406 pix->shared = 1;
407 scr->menu_shade_indicator = pix;
409 create_logo_image(scr);
411 scr->dock_dots = make3Dots(scr);
413 /* titlebar button pixmaps */
414 allocButtonPixmaps(scr);
417 void create_logo_image(WScreen *scr)
419 RImage *image = get_icon_image(scr, "Logo", "WMPanel", wPreferences.icon_size);
421 if (!image) {
422 wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
423 } else {
424 WMSetApplicationIconImage(scr->wmscreen, image);
425 RReleaseImage(image);
430 *----------------------------------------------------------------------
431 * createInternalWindows--
432 * Creates some windows used internally by the program. One to
433 * receive input focus when no other window can get it and another
434 * to display window geometry information during window resize/move.
436 * Returns:
437 * Nothing
439 * Side effects:
440 * Windows are created and some colors are allocated for the
441 * window background.
442 *----------------------------------------------------------------------
444 static void createInternalWindows(WScreen * scr)
446 int vmask;
447 XSetWindowAttributes attribs;
449 /* InputOnly window to get the focus when no other window can get it */
450 vmask = CWEventMask | CWOverrideRedirect;
451 attribs.event_mask = KeyPressMask | FocusChangeMask;
452 attribs.override_redirect = True;
453 scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
454 InputOnly, CopyFromParent, vmask, &attribs);
455 XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
456 XMapWindow(dpy, scr->no_focus_win);
458 XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
460 /* shadow window for dock buttons */
461 vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
462 attribs.border_pixel = scr->black_pixel;
463 attribs.save_under = True;
464 attribs.override_redirect = True;
465 attribs.background_pixmap = None;
466 attribs.background_pixel = scr->white_pixel;
467 attribs.cursor = wCursor[WCUR_DEFAULT];
468 vmask |= CWColormap;
469 attribs.colormap = scr->w_colormap;
470 scr->dock_shadow =
471 XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
472 wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
474 /* workspace name */
475 vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
476 attribs.save_under = True;
477 attribs.override_redirect = True;
478 attribs.colormap = scr->w_colormap;
479 attribs.background_pixel = scr->icon_back_texture->normal.pixel;
480 attribs.border_pixel = 0; /* do not care */
481 scr->workspace_name =
482 XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
483 CopyFromParent, scr->w_visual, vmask, &attribs);
487 *----------------------------------------------------------------------
488 * wScreenInit--
489 * Initializes the window manager for the given screen and
490 * allocates a WScreen descriptor for it. Many resources are allocated
491 * for the screen and the root window is setup appropriately.
493 * Returns:
494 * The WScreen descriptor for the screen.
496 * Side effects:
497 * Many resources are allocated and the IconSize property is
498 * set on the root window.
499 * The program can be aborted if some fatal error occurs.
501 * TODO: User specifiable visual.
502 *----------------------------------------------------------------------
504 WScreen *wScreenInit(int screen_number)
506 WScreen *scr;
507 XIconSize icon_size[1];
508 RContextAttributes rattr;
509 long event_mask;
510 XErrorHandler oldHandler;
511 int i;
513 scr = wmalloc(sizeof(WScreen));
515 scr->stacking_list = WMCreateTreeBag();
517 /* initialize globals */
518 scr->screen = screen_number;
519 scr->root_win = RootWindow(dpy, screen_number);
520 scr->depth = DefaultDepth(dpy, screen_number);
521 scr->colormap = DefaultColormap(dpy, screen_number);
523 scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
524 scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
526 wInitXinerama(scr);
528 scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
529 scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
531 for (i = 0; i < wXineramaHeads(scr); ++i) {
532 WMRect rect = wGetRectForHead(scr, i);
533 scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
534 scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
535 scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
536 scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
539 scr->fakeGroupLeaders = WMCreateArray(16);
541 CantManageScreen = 0;
542 oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
544 event_mask = EVENT_MASK;
546 if (wPreferences.disable_root_mouse) {
547 event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
550 XSelectInput(dpy, scr->root_win, event_mask);
552 #ifdef KEEP_XKB_LOCK_STATUS
553 /* Only GroupLock doesn't work correctly in my system since right-alt
554 * can change mode while holding it too - ]d
556 if (wXkbSupported) {
557 XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
559 #endif /* KEEP_XKB_LOCK_STATUS */
561 #ifdef HAVE_XRANDR
562 if (has_randr)
563 XRRSelectInput(dpy, scr->root_win, RRScreenChangeNotifyMask);
564 #endif
566 XSync(dpy, False);
567 XSetErrorHandler(oldHandler);
569 if (CantManageScreen) {
570 wfree(scr);
571 return NULL;
574 XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
576 /* screen descriptor for raster graphic library */
577 rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
578 rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
580 /* if the std colormap stuff works ok, this will be ignored */
581 rattr.colors_per_channel = wPreferences.cmap_size;
582 if (rattr.colors_per_channel < 2)
583 rattr.colors_per_channel = 2;
585 /* Use standard colormap */
586 rattr.standard_colormap_mode = RUseStdColormap;
588 if (getWVisualID(screen_number) >= 0) {
589 rattr.flags |= RC_VisualID;
590 rattr.visualid = getWVisualID(screen_number);
593 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
595 if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
596 wwarning("%s", RMessageForError(RErrorCode));
598 rattr.flags &= ~RC_StandardColormap;
599 rattr.standard_colormap_mode = RUseStdColormap;
601 scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
604 if (!scr->rcontext) {
605 wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
606 wAbort(False);
607 } else {
608 char **formats;
609 int i = 0;
611 formats = RSupportedFileFormats();
612 if (formats) {
613 for (i = 0; formats[i] != NULL; i++) {
614 if (strcmp(formats[i], "TIFF") == 0) {
615 scr->flags.supports_tiff = 1;
616 break;
622 scr->w_win = scr->rcontext->drawable;
623 scr->w_visual = scr->rcontext->visual;
624 scr->w_depth = scr->rcontext->depth;
625 scr->w_colormap = scr->rcontext->cmap;
627 /* create screen descriptor for WINGs */
628 scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
630 if (!scr->wmscreen) {
631 wfatal(_("could not initialize WINGs widget set"));
632 return NULL;
635 scr->black = WMBlackColor(scr->wmscreen);
636 scr->white = WMWhiteColor(scr->wmscreen);
637 scr->gray = WMGrayColor(scr->wmscreen);
638 scr->darkGray = WMDarkGrayColor(scr->wmscreen);
640 scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
641 scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
642 scr->light_pixel = WMColorPixel(scr->gray);
643 scr->dark_pixel = WMColorPixel(scr->darkGray);
645 /* create GCs with default values */
646 allocGCs(scr);
648 /* for our window manager info notice board. Need to
649 * create before reading the defaults, because it will be used there.
651 scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
653 /* read defaults for this screen */
654 wReadDefaults(scr, WDWindowMaker->dictionary);
657 XColor xcol;
658 /* frame boder color */
659 wGetColor(scr, WMGetColorRGBDescription(scr->frame_border_color), &xcol);
660 scr->frame_border_pixel = xcol.pixel;
661 wGetColor(scr, WMGetColorRGBDescription(scr->frame_selected_border_color), &xcol);
662 scr->frame_selected_border_pixel = xcol.pixel;
665 createInternalWindows(scr);
667 wNETWMInitStuff(scr);
669 /* create initial workspace */
670 wWorkspaceNew(scr);
672 /* create shared pixmaps */
673 createPixmaps(scr);
675 /* set icon sizes we can accept from clients */
676 icon_size[0].min_width = 8;
677 icon_size[0].min_height = 8;
678 icon_size[0].max_width = wPreferences.icon_size - 4;
679 icon_size[0].max_height = wPreferences.icon_size - 4;
680 icon_size[0].width_inc = 1;
681 icon_size[0].height_inc = 1;
682 XSetIconSizes(dpy, scr->root_win, icon_size, 1);
684 /* setup WindowMaker protocols property in the root window */
685 PropSetWMakerProtocols(scr->root_win);
687 /* setup our noticeboard */
688 XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
689 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
690 XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
691 XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
693 #ifdef BALLOON_TEXT
694 /* initialize balloon text stuff */
695 wBalloonInitialize(scr);
696 #endif
698 scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
700 scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
701 if (!scr->tech_draw_font)
702 scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
704 scr->gview = WCreateGeometryView(scr->wmscreen);
705 WMRealizeWidget(scr->gview);
707 wScreenUpdateUsableArea(scr);
709 return scr;
712 void wScreenUpdateUsableArea(WScreen * scr)
715 * scr->totalUsableArea[] will become the usableArea used for Windowplacement,
716 * scr->usableArea[] will be used for iconplacement, hence no iconyard nor
717 * border.
720 WArea area;
721 int i, dock_head;
722 unsigned long best_area, tmp_area;
723 unsigned int size, position;
725 dock_head = scr->xine_info.primary_head;
726 best_area = 0;
727 size = wPreferences.workspace_border_size;
728 position = wPreferences.workspace_border_position;
730 if (scr->dock) {
731 WMRect rect;
732 rect.pos.x = scr->dock->x_pos;
733 rect.pos.y = scr->dock->y_pos;
734 rect.size.width = wPreferences.icon_size;
735 rect.size.height = wPreferences.icon_size;
736 dock_head = wGetHeadForRect(scr, rect);
739 for (i = 0; i < wXineramaHeads(scr); ++i) {
740 WMRect rect = wGetRectForHead(scr, i);
741 scr->totalUsableArea[i].x1 = rect.pos.x;
742 scr->totalUsableArea[i].y1 = rect.pos.y;
743 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
744 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
746 if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
747 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
749 if (scr->dock->on_right_side) {
750 scr->totalUsableArea[i].x2 -= offset;
751 } else {
752 scr->totalUsableArea[i].x1 += offset;
756 if (wNETWMGetUsableArea(scr, i, &area)) {
757 scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
758 scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
759 scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
760 scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
763 scr->usableArea[i] = scr->totalUsableArea[i];
765 #if 0
766 printf("usableArea[%d]: %d %d %d %d\n", i,
767 scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
768 #endif
769 if (wPreferences.no_window_over_icons) {
770 if (wPreferences.icon_yard & IY_VERT) {
771 if (wPreferences.icon_yard & IY_RIGHT) {
772 scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
773 } else {
774 scr->totalUsableArea[i].x1 += wPreferences.icon_size;
776 } else {
777 if (wPreferences.icon_yard & IY_TOP) {
778 scr->totalUsableArea[i].y1 += wPreferences.icon_size;
779 } else {
780 scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
785 if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
786 scr->totalUsableArea[i].x1 = rect.pos.x;
787 scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
790 if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
791 scr->totalUsableArea[i].y1 = rect.pos.y;
792 scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
795 tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
796 (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
798 if (tmp_area > best_area) {
799 best_area = tmp_area;
800 area = scr->totalUsableArea[i];
803 if (size > 0 && position != WB_NONE) {
804 if (position & WB_LEFTRIGHT) {
805 scr->totalUsableArea[i].x1 += size;
806 scr->totalUsableArea[i].x2 -= size;
808 if (position & WB_TOPBOTTOM) {
809 scr->totalUsableArea[i].y1 += size;
810 scr->totalUsableArea[i].y2 -= size;
815 if (wPreferences.auto_arrange_icons)
816 wArrangeIcons(scr, True);
819 void wScreenRestoreState(WScreen * scr)
821 WMPropList *state;
822 char *path;
824 OpenRootMenu(scr, -10000, -10000, False);
825 wMenuUnmap(scr->root_menu);
827 make_keys();
829 if (wScreenCount == 1) {
830 path = wdefaultspathfordomain("WMState");
831 } else {
832 char buf[16];
833 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
834 path = wdefaultspathfordomain(buf);
836 scr->session_state = WMReadPropListFromFile(path);
837 wfree(path);
838 if (!scr->session_state && wScreenCount > 1) {
839 path = wdefaultspathfordomain("WMState");
840 scr->session_state = WMReadPropListFromFile(path);
841 wfree(path);
844 if (!scr->session_state) {
845 scr->session_state = WMCreatePLDictionary(NULL, NULL);
848 if (!wPreferences.flags.nodock) {
849 state = WMGetFromPLDictionary(scr->session_state, dDock);
850 scr->dock = wDockRestoreState(scr, state, WM_DOCK);
851 /* If clip_merged_in_dock, setting scr->clip_icon is done by
852 * wDockRestoreState()->wDockCreate()->mainIconCreate() */
855 if (!wPreferences.flags.noclip) {
856 state = WMGetFromPLDictionary(scr->session_state, dClip);
857 scr->clip_icon = wClipRestoreState(scr, state);
860 if (!wPreferences.flags.nodrawer) {
861 wDrawersRestoreState(scr);
864 wWorkspaceRestoreState(scr);
866 wScreenUpdateUsableArea(scr);
869 void wScreenSaveState(WScreen * scr)
871 WWindow *wwin;
872 char *str;
873 WMPropList *old_state, *foo;
875 make_keys();
877 /* save state of windows */
878 wwin = scr->focused_window;
879 while (wwin) {
880 wWindowSaveState(wwin);
881 wwin = wwin->prev;
884 if (wPreferences.flags.noupdates)
885 return;
887 old_state = scr->session_state;
888 scr->session_state = WMCreatePLDictionary(NULL, NULL);
890 WMPLSetCaseSensitive(True);
892 /* save dock state to file */
893 if (!wPreferences.flags.nodock) {
894 wDockSaveState(scr, old_state);
895 } else {
896 if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
897 WMPutInPLDictionary(scr->session_state, dDock, foo);
900 if (!wPreferences.flags.noclip) {
901 wClipSaveState(scr);
902 } else {
903 if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
904 WMPutInPLDictionary(scr->session_state, dClip, foo);
908 wWorkspaceSaveState(scr, old_state);
910 if (!wPreferences.flags.nodrawer) {
911 wDrawersSaveState(scr);
912 } else {
913 if ((foo = WMGetFromPLDictionary(old_state, dDrawers)) != NULL) {
914 WMPutInPLDictionary(scr->session_state, dDrawers, foo);
919 if (wPreferences.save_session_on_exit) {
920 wSessionSaveState(scr);
921 } else {
922 if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
923 WMPutInPLDictionary(scr->session_state, dApplications, foo);
925 if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
926 WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
930 /* clean up */
931 WMPLSetCaseSensitive(False);
933 wMenuSaveState(scr);
935 if (wScreenCount == 1) {
936 str = wdefaultspathfordomain("WMState");
937 } else {
938 char buf[16];
939 snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
940 str = wdefaultspathfordomain(buf);
942 if (!WMWritePropListToFile(scr->session_state, str)) {
943 werror(_("could not save session state in %s"), str);
945 wfree(str);
946 WMReleasePropList(old_state);
949 int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
951 int moved = 0;
952 int tol_w, tol_h;
954 * With respect to the head that contains most of the window.
956 int sx1, sy1, sx2, sy2;
958 WMRect rect;
959 int head, flags;
961 rect.pos.x = *x;
962 rect.pos.y = *y;
963 rect.size.width = width;
964 rect.size.height = height;
966 head = wGetRectPlacementInfo(scr, rect, &flags);
967 rect = wGetRectForHead(scr, head);
969 sx1 = rect.pos.x;
970 sy1 = rect.pos.y;
971 sx2 = sx1 + rect.size.width;
972 sy2 = sy1 + rect.size.height;
974 #if 0 /* NOTE: gives funky group movement */
975 if (flags & XFLAG_MULTIPLE) {
977 * since we span multiple heads, pull window totaly inside
979 if (*x < sx1)
980 *x = sx1, moved = 1;
981 else if (*x + width > sx2)
982 *x = sx2 - width, moved = 1;
984 if (*y < sy1)
985 *y = sy1, moved = 1;
986 else if (*y + height > sy2)
987 *y = sy2 - height, moved = 1;
989 return moved;
991 #endif
993 if (width > 20)
994 tol_w = width / 2;
995 else
996 tol_w = 20;
998 if (height > 20)
999 tol_h = height / 2;
1000 else
1001 tol_h = 20;
1003 if (*x + width < sx1 + 10)
1004 *x = sx1 - tol_w, moved = 1;
1005 else if (*x >= sx2 - 10)
1006 *x = sx2 - tol_w - 1, moved = 1;
1008 if (*y < sy1 - height + 10)
1009 *y = sy1 - tol_h, moved = 1;
1010 else if (*y >= sy2 - 10)
1011 *y = sy2 - tol_h - 1, moved = 1;
1013 return moved;
1016 int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
1018 int moved = 0;
1019 int sx1, sy1, sx2, sy2;
1020 WMRect rect;
1021 int head;
1023 rect.pos.x = *x;
1024 rect.pos.y = *y;
1025 rect.size.width = width;
1026 rect.size.height = height;
1028 head = wGetHeadForRect(scr, rect);
1029 rect = wGetRectForHead(scr, head);
1031 sx1 = rect.pos.x;
1032 sy1 = rect.pos.y;
1033 sx2 = sx1 + rect.size.width;
1034 sy2 = sy1 + rect.size.height;
1036 if (*x < sx1)
1037 *x = sx1, moved = 1;
1038 else if (*x + width > sx2)
1039 *x = sx2 - width, moved = 1;
1041 if (*y < sy1)
1042 *y = sy1, moved = 1;
1043 else if (*y + height > sy2)
1044 *y = sy2 - height, moved = 1;
1046 return moved;