00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <config.h>
00030 #include "screen-private.h"
00031 #include "util.h"
00032 #include "errors.h"
00033 #include "window-private.h"
00034 #include "frame-private.h"
00035 #include "prefs.h"
00036 #include "workspace.h"
00037 #include "keybindings.h"
00038 #include "stack.h"
00039 #include "xprops.h"
00040 #include "compositor.h"
00041
00042 #ifdef HAVE_SOLARIS_XINERAMA
00043 #include <X11/extensions/xinerama.h>
00044 #endif
00045 #ifdef HAVE_XFREE_XINERAMA
00046 #include <X11/extensions/Xinerama.h>
00047 #endif
00048
00049 #include <X11/Xatom.h>
00050 #include <locale.h>
00051 #include <string.h>
00052 #include <stdio.h>
00053
00054 static char* get_screen_name (MetaDisplay *display,
00055 int number);
00056
00057 static void update_num_workspaces (MetaScreen *screen,
00058 guint32 timestamp);
00059 static void update_focus_mode (MetaScreen *screen);
00060 static void set_workspace_names (MetaScreen *screen);
00061 static void prefs_changed_callback (MetaPreference pref,
00062 gpointer data);
00063
00064 static void set_desktop_geometry_hint (MetaScreen *screen);
00065 static void set_desktop_viewport_hint (MetaScreen *screen);
00066
00067 #ifdef HAVE_STARTUP_NOTIFICATION
00068 static void meta_screen_sn_event (SnMonitorEvent *event,
00069 void *user_data);
00070 #endif
00071
00072 static int
00073 set_wm_check_hint (MetaScreen *screen)
00074 {
00075 unsigned long data[1];
00076
00077 g_return_val_if_fail (screen->display->leader_window != None, 0);
00078
00079 data[0] = screen->display->leader_window;
00080
00081 XChangeProperty (screen->display->xdisplay, screen->xroot,
00082 screen->display->atom__NET_SUPPORTING_WM_CHECK,
00083 XA_WINDOW,
00084 32, PropModeReplace, (guchar*) data, 1);
00085
00086 return Success;
00087 }
00088
00089 static int
00090 set_supported_hint (MetaScreen *screen)
00091 {
00092 Atom atoms[] = {
00093 #define EWMH_ATOMS_ONLY
00094 #define item(x) screen->display->atom_##x,
00095 #include "atomnames.h"
00096 #undef item
00097 #undef EWMH_ATOMS_ONLY
00098 };
00099
00100 XChangeProperty (screen->display->xdisplay, screen->xroot,
00101 screen->display->atom__NET_SUPPORTED,
00102 XA_ATOM,
00103 32, PropModeReplace,
00104 (guchar*) atoms, G_N_ELEMENTS(atoms));
00105
00106 return Success;
00107 }
00108
00109 static int
00110 set_wm_icon_size_hint (MetaScreen *screen)
00111 {
00112 #define N_VALS 6
00113 gulong vals[N_VALS];
00114
00115
00116 vals[0] = META_ICON_WIDTH;
00117 vals[1] = META_ICON_HEIGHT;
00118 vals[2] = META_ICON_WIDTH;
00119 vals[3] = META_ICON_HEIGHT;
00120 vals[4] = 0;
00121 vals[5] = 0;
00122
00123 XChangeProperty (screen->display->xdisplay, screen->xroot,
00124 screen->display->atom_WM_ICON_SIZE,
00125 XA_CARDINAL,
00126 32, PropModeReplace, (guchar*) vals, N_VALS);
00127
00128 return Success;
00129 #undef N_VALS
00130 }
00131
00132 static void
00133 reload_xinerama_infos (MetaScreen *screen)
00134 {
00135 MetaDisplay *display;
00136
00137 {
00138 GList *tmp;
00139
00140 tmp = screen->workspaces;
00141 while (tmp != NULL)
00142 {
00143 MetaWorkspace *space = tmp->data;
00144
00145 meta_workspace_invalidate_work_area (space);
00146
00147 tmp = tmp->next;
00148 }
00149 }
00150
00151 display = screen->display;
00152
00153 if (screen->xinerama_infos)
00154 g_free (screen->xinerama_infos);
00155
00156 screen->xinerama_infos = NULL;
00157 screen->n_xinerama_infos = 0;
00158 screen->last_xinerama_index = 0;
00159
00160 screen->display->xinerama_cache_invalidated = TRUE;
00161
00162 #ifdef HAVE_XFREE_XINERAMA
00163 if (XineramaIsActive (display->xdisplay))
00164 {
00165 XineramaScreenInfo *infos;
00166 int n_infos;
00167 int i;
00168
00169 n_infos = 0;
00170 infos = XineramaQueryScreens (display->xdisplay, &n_infos);
00171
00172 meta_topic (META_DEBUG_XINERAMA,
00173 "Found %d Xinerama screens on display %s\n",
00174 n_infos, display->name);
00175
00176 if (n_infos > 0)
00177 {
00178 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_infos);
00179 screen->n_xinerama_infos = n_infos;
00180
00181 i = 0;
00182 while (i < n_infos)
00183 {
00184 screen->xinerama_infos[i].number = infos[i].screen_number;
00185 screen->xinerama_infos[i].rect.x = infos[i].x_org;
00186 screen->xinerama_infos[i].rect.y = infos[i].y_org;
00187 screen->xinerama_infos[i].rect.width = infos[i].width;
00188 screen->xinerama_infos[i].rect.height = infos[i].height;
00189
00190 meta_topic (META_DEBUG_XINERAMA,
00191 "Xinerama %d is %d,%d %d x %d\n",
00192 screen->xinerama_infos[i].number,
00193 screen->xinerama_infos[i].rect.x,
00194 screen->xinerama_infos[i].rect.y,
00195 screen->xinerama_infos[i].rect.width,
00196 screen->xinerama_infos[i].rect.height);
00197
00198 ++i;
00199 }
00200 }
00201
00202 meta_XFree (infos);
00203 }
00204 else
00205 {
00206 meta_topic (META_DEBUG_XINERAMA,
00207 "No XFree86 Xinerama extension or XFree86 Xinerama inactive on display %s\n",
00208 display->name);
00209 }
00210 #else
00211 meta_topic (META_DEBUG_XINERAMA,
00212 "Metacity compiled without XFree86 Xinerama support\n");
00213 #endif
00214
00215 #ifdef HAVE_SOLARIS_XINERAMA
00216
00217 if (screen->n_xinerama_infos == 0 &&
00218 XineramaGetState (screen->display->xdisplay,
00219 screen->number))
00220 {
00221 XRectangle monitors[MAXFRAMEBUFFERS];
00222 unsigned char hints[16];
00223 int result;
00224 int n_monitors;
00225 int i;
00226
00227 n_monitors = 0;
00228 result = XineramaGetInfo (screen->display->xdisplay,
00229 screen->number,
00230 monitors, hints,
00231 &n_monitors);
00232
00233
00234
00235 if (result > 0)
00236 {
00237 g_assert (n_monitors > 0);
00238
00239 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, n_monitors);
00240 screen->n_xinerama_infos = n_monitors;
00241
00242 i = 0;
00243 while (i < n_monitors)
00244 {
00245 screen->xinerama_infos[i].number = i;
00246 screen->xinerama_infos[i].rect.x = monitors[i].x;
00247 screen->xinerama_infos[i].rect.y = monitors[i].y;
00248 screen->xinerama_infos[i].rect.width = monitors[i].width;
00249 screen->xinerama_infos[i].rect.height = monitors[i].height;
00250
00251 meta_topic (META_DEBUG_XINERAMA,
00252 "Xinerama %d is %d,%d %d x %d\n",
00253 screen->xinerama_infos[i].number,
00254 screen->xinerama_infos[i].rect.x,
00255 screen->xinerama_infos[i].rect.y,
00256 screen->xinerama_infos[i].rect.width,
00257 screen->xinerama_infos[i].rect.height);
00258
00259 ++i;
00260 }
00261 }
00262 }
00263 else if (screen->n_xinerama_infos == 0)
00264 {
00265 meta_topic (META_DEBUG_XINERAMA,
00266 "No Solaris Xinerama extension or Solaris Xinerama inactive on display %s\n",
00267 display->name);
00268 }
00269 #else
00270 meta_topic (META_DEBUG_XINERAMA,
00271 "Metacity compiled without Solaris Xinerama support\n");
00272 #endif
00273
00274
00275
00276
00277
00278 if (screen->n_xinerama_infos == 0)
00279 {
00280 if (g_getenv ("METACITY_DEBUG_XINERAMA"))
00281 {
00282 meta_topic (META_DEBUG_XINERAMA,
00283 "Pretending a single monitor has two Xinerama screens\n");
00284
00285 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 2);
00286 screen->n_xinerama_infos = 2;
00287
00288 screen->xinerama_infos[0].number = 0;
00289 screen->xinerama_infos[0].rect = screen->rect;
00290 screen->xinerama_infos[0].rect.width = screen->rect.width / 2;
00291
00292 screen->xinerama_infos[1].number = 1;
00293 screen->xinerama_infos[1].rect = screen->rect;
00294 screen->xinerama_infos[1].rect.x = screen->rect.width / 2;
00295 screen->xinerama_infos[1].rect.width = screen->rect.width / 2;
00296 }
00297 else
00298 {
00299 meta_topic (META_DEBUG_XINERAMA,
00300 "No Xinerama screens, using default screen info\n");
00301
00302 screen->xinerama_infos = g_new (MetaXineramaScreenInfo, 1);
00303 screen->n_xinerama_infos = 1;
00304
00305 screen->xinerama_infos[0].number = 0;
00306 screen->xinerama_infos[0].rect = screen->rect;
00307 }
00308 }
00309
00310 g_assert (screen->n_xinerama_infos > 0);
00311 g_assert (screen->xinerama_infos != NULL);
00312 }
00313
00314 MetaScreen*
00315 meta_screen_new (MetaDisplay *display,
00316 int number,
00317 guint32 timestamp)
00318 {
00319 MetaScreen *screen;
00320 Window xroot;
00321 Display *xdisplay;
00322 XWindowAttributes attr;
00323 Window new_wm_sn_owner;
00324 Window current_wm_sn_owner;
00325 gboolean replace_current_wm;
00326 Atom wm_sn_atom;
00327 char buf[128];
00328 guint32 manager_timestamp;
00329 gulong current_workspace;
00330
00331 replace_current_wm = meta_get_replace_current_wm ();
00332
00333
00334
00335
00336
00337
00338 xdisplay = display->xdisplay;
00339
00340 meta_verbose ("Trying screen %d on display '%s'\n",
00341 number, display->name);
00342
00343 xroot = RootWindow (xdisplay, number);
00344
00345
00346
00347
00348 if (xroot == None)
00349 {
00350 meta_warning (_("Screen %d on display '%s' is invalid\n"),
00351 number, display->name);
00352 return NULL;
00353 }
00354
00355 sprintf (buf, "WM_S%d", number);
00356 wm_sn_atom = XInternAtom (xdisplay, buf, False);
00357
00358 current_wm_sn_owner = XGetSelectionOwner (xdisplay, wm_sn_atom);
00359
00360 if (current_wm_sn_owner != None)
00361 {
00362 XSetWindowAttributes attrs;
00363
00364 if (!replace_current_wm)
00365 {
00366 meta_warning (_("Screen %d on display \"%s\" already has a window manager; try using the --replace option to replace the current window manager.\n"),
00367 number, display->name);
00368
00369 return NULL;
00370 }
00371
00372
00373 meta_error_trap_push_with_return (display);
00374 attrs.event_mask = StructureNotifyMask;
00375 XChangeWindowAttributes (xdisplay,
00376 current_wm_sn_owner, CWEventMask, &attrs);
00377 if (meta_error_trap_pop_with_return (display, FALSE) != Success)
00378 current_wm_sn_owner = None;
00379 }
00380
00381
00382
00383
00384 new_wm_sn_owner = meta_create_offscreen_window (xdisplay, xroot, NoEventMask);
00385
00386 manager_timestamp = timestamp;
00387
00388 XSetSelectionOwner (xdisplay, wm_sn_atom, new_wm_sn_owner,
00389 manager_timestamp);
00390
00391 if (XGetSelectionOwner (xdisplay, wm_sn_atom) != new_wm_sn_owner)
00392 {
00393 meta_warning (_("Could not acquire window manager selection on screen %d display \"%s\"\n"),
00394 number, display->name);
00395
00396 XDestroyWindow (xdisplay, new_wm_sn_owner);
00397
00398 return NULL;
00399 }
00400
00401 {
00402
00403 XClientMessageEvent ev;
00404
00405 ev.type = ClientMessage;
00406 ev.window = xroot;
00407 ev.message_type = display->atom_MANAGER;
00408 ev.format = 32;
00409 ev.data.l[0] = manager_timestamp;
00410 ev.data.l[1] = wm_sn_atom;
00411
00412 XSendEvent (xdisplay, xroot, False, StructureNotifyMask, (XEvent*)&ev);
00413 }
00414
00415
00416 if (current_wm_sn_owner != None)
00417 {
00418 XEvent event;
00419
00420
00421
00422 meta_verbose ("Waiting for old window manager to exit\n");
00423 do
00424 {
00425 XWindowEvent (xdisplay, current_wm_sn_owner,
00426 StructureNotifyMask, &event);
00427 }
00428 while (event.type != DestroyNotify);
00429 }
00430
00431
00432 meta_error_trap_push_with_return (display);
00433
00434
00435
00436
00437 XGetWindowAttributes (xdisplay, xroot, &attr);
00438 XSelectInput (xdisplay,
00439 xroot,
00440 SubstructureRedirectMask | SubstructureNotifyMask |
00441 ColormapChangeMask | PropertyChangeMask |
00442 LeaveWindowMask | EnterWindowMask |
00443 KeyPressMask | KeyReleaseMask |
00444 FocusChangeMask | StructureNotifyMask |
00445 #ifdef HAVE_COMPOSITE_EXTENSIONS
00446 ExposureMask |
00447 #endif
00448 attr.your_event_mask);
00449 if (meta_error_trap_pop_with_return (display, FALSE) != Success)
00450 {
00451 meta_warning (_("Screen %d on display \"%s\" already has a window manager\n"),
00452 number, display->name);
00453
00454 XDestroyWindow (xdisplay, new_wm_sn_owner);
00455
00456 return NULL;
00457 }
00458
00459 screen = g_new (MetaScreen, 1);
00460 screen->closing = 0;
00461
00462 screen->display = display;
00463 screen->number = number;
00464 screen->screen_name = get_screen_name (display, number);
00465 screen->xscreen = ScreenOfDisplay (xdisplay, number);
00466 screen->xroot = xroot;
00467 screen->rect.x = screen->rect.y = 0;
00468 screen->rect.width = WidthOfScreen (screen->xscreen);
00469 screen->rect.height = HeightOfScreen (screen->xscreen);
00470 screen->current_cursor = -1;
00471 screen->default_xvisual = DefaultVisualOfScreen (screen->xscreen);
00472 screen->default_depth = DefaultDepthOfScreen (screen->xscreen);
00473 screen->flash_window = None;
00474
00475 screen->wm_sn_selection_window = new_wm_sn_owner;
00476 screen->wm_sn_atom = wm_sn_atom;
00477 screen->wm_sn_timestamp = manager_timestamp;
00478
00479 #ifdef HAVE_COMPOSITE_EXTENSIONS
00480 screen->wm_cm_selection_window = meta_create_offscreen_window (xdisplay,
00481 xroot,
00482 NoEventMask);
00483 #endif
00484 screen->work_area_idle = 0;
00485
00486 screen->active_workspace = NULL;
00487 screen->workspaces = NULL;
00488 screen->rows_of_workspaces = 1;
00489 screen->columns_of_workspaces = -1;
00490 screen->vertical_workspaces = FALSE;
00491 screen->starting_corner = META_SCREEN_TOPLEFT;
00492 screen->compositor_data = NULL;
00493
00494 {
00495 XFontStruct *font_info;
00496 XGCValues gc_values;
00497 gulong value_mask = 0;
00498
00499 gc_values.subwindow_mode = IncludeInferiors;
00500 value_mask |= GCSubwindowMode;
00501 gc_values.function = GXinvert;
00502 value_mask |= GCFunction;
00503 gc_values.line_width = META_WIREFRAME_XOR_LINE_WIDTH;
00504 value_mask |= GCLineWidth;
00505
00506 font_info = XLoadQueryFont (screen->display->xdisplay, "fixed");
00507
00508 if (font_info != NULL)
00509 {
00510 gc_values.font = font_info->fid;
00511 value_mask |= GCFont;
00512 XFreeFontInfo (NULL, font_info, 1);
00513 }
00514 else
00515 meta_warning ("xserver doesn't have 'fixed' font.\n");
00516
00517 screen->root_xor_gc = XCreateGC (screen->display->xdisplay,
00518 screen->xroot,
00519 value_mask,
00520 &gc_values);
00521 }
00522
00523 screen->xinerama_infos = NULL;
00524 screen->n_xinerama_infos = 0;
00525 screen->last_xinerama_index = 0;
00526
00527 reload_xinerama_infos (screen);
00528
00529 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
00530
00531
00532 screen->no_focus_window =
00533 meta_create_offscreen_window (display->xdisplay,
00534 screen->xroot,
00535 FocusChangeMask|KeyPressMask|KeyReleaseMask);
00536 XMapWindow (display->xdisplay, screen->no_focus_window);
00537
00538
00539 set_wm_icon_size_hint (screen);
00540
00541 set_supported_hint (screen);
00542
00543 set_wm_check_hint (screen);
00544
00545 set_desktop_viewport_hint (screen);
00546
00547 set_desktop_geometry_hint (screen);
00548
00549 meta_screen_update_workspace_layout (screen);
00550
00551
00552 current_workspace = 0;
00553 if (meta_prop_get_cardinal (screen->display,
00554 screen->xroot,
00555 screen->display->atom__NET_CURRENT_DESKTOP,
00556 ¤t_workspace))
00557 meta_verbose ("Read existing _NET_CURRENT_DESKTOP = %d\n",
00558 (int) current_workspace);
00559 else
00560 meta_verbose ("No _NET_CURRENT_DESKTOP present\n");
00561
00562
00563
00564
00565 meta_workspace_activate (meta_workspace_new (screen), timestamp);
00566 update_num_workspaces (screen, timestamp);
00567
00568 set_workspace_names (screen);
00569
00570 screen->all_keys_grabbed = FALSE;
00571 screen->keys_grabbed = FALSE;
00572 meta_screen_grab_keys (screen);
00573
00574 screen->ui = meta_ui_new (screen->display->xdisplay,
00575 screen->xscreen);
00576
00577 screen->tab_popup = NULL;
00578
00579 screen->stack = meta_stack_new (screen);
00580
00581 meta_prefs_add_listener (prefs_changed_callback, screen);
00582
00583 #ifdef HAVE_STARTUP_NOTIFICATION
00584 screen->sn_context =
00585 sn_monitor_context_new (screen->display->sn_display,
00586 screen->number,
00587 meta_screen_sn_event,
00588 screen,
00589 NULL);
00590 screen->startup_sequences = NULL;
00591 screen->startup_sequence_timeout = 0;
00592 #endif
00593
00594
00595 {
00596 MetaWorkspace *space;
00597
00598 space = meta_screen_get_workspace_by_index (screen,
00599 current_workspace);
00600
00601 if (space != NULL)
00602 meta_workspace_activate (space, timestamp);
00603 }
00604
00605 meta_verbose ("Added screen %d ('%s') root 0x%lx\n",
00606 screen->number, screen->screen_name, screen->xroot);
00607
00608 return screen;
00609 }
00610
00611 void
00612 meta_screen_free (MetaScreen *screen,
00613 guint32 timestamp)
00614 {
00615 MetaDisplay *display;
00616 XGCValues gc_values = { 0 };
00617
00618 display = screen->display;
00619
00620 screen->closing += 1;
00621
00622 meta_display_grab (display);
00623
00624 if (screen->display->compositor)
00625 {
00626 meta_compositor_unmanage_screen (screen->display->compositor,
00627 screen);
00628 }
00629
00630 meta_display_unmanage_windows_for_screen (display, screen, timestamp);
00631
00632 meta_prefs_remove_listener (prefs_changed_callback, screen);
00633
00634 meta_screen_ungrab_keys (screen);
00635
00636 #ifdef HAVE_STARTUP_NOTIFICATION
00637 g_slist_foreach (screen->startup_sequences,
00638 (GFunc) sn_startup_sequence_unref, NULL);
00639 g_slist_free (screen->startup_sequences);
00640 screen->startup_sequences = NULL;
00641
00642 if (screen->startup_sequence_timeout != 0)
00643 {
00644 g_source_remove (screen->startup_sequence_timeout);
00645 screen->startup_sequence_timeout = 0;
00646 }
00647 if (screen->sn_context)
00648 {
00649 sn_monitor_context_unref (screen->sn_context);
00650 screen->sn_context = NULL;
00651 }
00652 #endif
00653
00654 meta_ui_free (screen->ui);
00655
00656 meta_stack_free (screen->stack);
00657
00658 meta_error_trap_push_with_return (screen->display);
00659 XSelectInput (screen->display->xdisplay, screen->xroot, 0);
00660 if (meta_error_trap_pop_with_return (screen->display, FALSE) != Success)
00661 meta_warning (_("Could not release screen %d on display \"%s\"\n"),
00662 screen->number, screen->display->name);
00663
00664 XDestroyWindow (screen->display->xdisplay,
00665 screen->wm_sn_selection_window);
00666
00667 if (screen->work_area_idle != 0)
00668 g_source_remove (screen->work_area_idle);
00669
00670
00671 if (XGetGCValues (screen->display->xdisplay,
00672 screen->root_xor_gc,
00673 GCFont,
00674 &gc_values))
00675 {
00676 XUnloadFont (screen->display->xdisplay,
00677 gc_values.font);
00678 }
00679
00680 XFreeGC (screen->display->xdisplay,
00681 screen->root_xor_gc);
00682
00683 if (screen->xinerama_infos)
00684 g_free (screen->xinerama_infos);
00685
00686 g_free (screen->screen_name);
00687 g_free (screen);
00688
00689 XFlush (display->xdisplay);
00690 meta_display_ungrab (display);
00691 }
00692
00693 typedef struct
00694 {
00695 Window xwindow;
00696 XWindowAttributes attrs;
00697 } WindowInfo;
00698
00699 static GList *
00700 list_windows (MetaScreen *screen)
00701 {
00702 Window ignored1, ignored2;
00703 Window *children;
00704 guint n_children, i;
00705 GList *result;
00706
00707 XQueryTree (screen->display->xdisplay,
00708 screen->xroot,
00709 &ignored1, &ignored2, &children, &n_children);
00710
00711 result = NULL;
00712 for (i = 0; i < n_children; ++i)
00713 {
00714 WindowInfo *info = g_new0 (WindowInfo, 1);
00715
00716 meta_error_trap_push_with_return (screen->display);
00717
00718 XGetWindowAttributes (screen->display->xdisplay,
00719 children[i], &info->attrs);
00720
00721 if (meta_error_trap_pop_with_return (screen->display, TRUE))
00722 {
00723 meta_verbose ("Failed to get attributes for window 0x%lx\n",
00724 children[i]);
00725 g_free (info);
00726 }
00727 else
00728 {
00729 info->xwindow = children[i];
00730 }
00731
00732 result = g_list_prepend (result, info);
00733 }
00734
00735 if (children)
00736 XFree (children);
00737
00738 return g_list_reverse (result);
00739 }
00740
00741 void
00742 meta_screen_manage_all_windows (MetaScreen *screen)
00743 {
00744 GList *windows;
00745 GList *list;
00746
00747 meta_display_grab (screen->display);
00748
00749 windows = list_windows (screen);
00750
00751 meta_stack_freeze (screen->stack);
00752 for (list = windows; list != NULL; list = list->next)
00753 {
00754 WindowInfo *info = list->data;
00755 MetaWindow *window;
00756
00757 window = meta_window_new_with_attrs (screen->display, info->xwindow, TRUE,
00758 &info->attrs);
00759 if (info->xwindow == screen->no_focus_window ||
00760 info->xwindow == screen->flash_window ||
00761 #ifdef HAVE_COMPOSITE_EXTENSIONS
00762 info->xwindow == screen->wm_cm_selection_window ||
00763 #endif
00764 info->xwindow == screen->wm_sn_selection_window) {
00765 meta_verbose ("Not managing our own windows\n");
00766 continue;
00767 }
00768
00769 if (screen->display->compositor)
00770 meta_compositor_add_window (screen->display->compositor, window,
00771 info->xwindow, &info->attrs);
00772 }
00773 meta_stack_thaw (screen->stack);
00774
00775 g_list_foreach (windows, (GFunc)g_free, NULL);
00776 g_list_free (windows);
00777
00778 meta_display_ungrab (screen->display);
00779 }
00780
00781 void
00782 meta_screen_composite_all_windows (MetaScreen *screen)
00783 {
00784 #ifdef HAVE_COMPOSITE_EXTENSIONS
00785 MetaDisplay *display;
00786 GList *windows, *list;
00787
00788 display = screen->display;
00789 if (!display->compositor)
00790 return;
00791
00792 windows = list_windows (screen);
00793
00794 meta_stack_freeze (screen->stack);
00795
00796 for (list = windows; list != NULL; list = list->next)
00797 {
00798 WindowInfo *info = list->data;
00799
00800 if (info->xwindow == screen->no_focus_window ||
00801 info->xwindow == screen->flash_window ||
00802 info->xwindow == screen->wm_sn_selection_window ||
00803 info->xwindow == screen->wm_cm_selection_window) {
00804 meta_verbose ("Not managing our own windows\n");
00805 continue;
00806 }
00807
00808 meta_compositor_add_window (display->compositor,
00809 meta_display_lookup_x_window (display,
00810 info->xwindow),
00811 info->xwindow, &info->attrs);
00812 }
00813
00814 meta_stack_thaw (screen->stack);
00815
00816 g_list_foreach (windows, (GFunc)g_free, NULL);
00817 g_list_free (windows);
00818 #endif
00819 }
00820
00821 MetaScreen*
00822 meta_screen_for_x_screen (Screen *xscreen)
00823 {
00824 MetaDisplay *display;
00825
00826 display = meta_display_for_x_display (DisplayOfScreen (xscreen));
00827
00828 if (display == NULL)
00829 return NULL;
00830
00831 return meta_display_screen_for_x_screen (display, xscreen);
00832 }
00833
00834 static void
00835 prefs_changed_callback (MetaPreference pref,
00836 gpointer data)
00837 {
00838 MetaScreen *screen = data;
00839
00840 if (pref == META_PREF_NUM_WORKSPACES)
00841 {
00842
00843
00844
00845 guint32 timestamp =
00846 meta_display_get_current_time_roundtrip (screen->display);
00847 update_num_workspaces (screen, timestamp);
00848 }
00849 else if (pref == META_PREF_FOCUS_MODE)
00850 {
00851 update_focus_mode (screen);
00852 }
00853 else if (pref == META_PREF_WORKSPACE_NAMES)
00854 {
00855 set_workspace_names (screen);
00856 }
00857 }
00858
00859
00860 static char*
00861 get_screen_name (MetaDisplay *display,
00862 int number)
00863 {
00864 char *p;
00865 char *dname;
00866 char *scr;
00867
00868
00869
00870
00871 dname = g_strdup (DisplayString (display->xdisplay));
00872
00873
00874
00875 p = strrchr (dname, ':');
00876 if (p)
00877 {
00878 p = strchr (p, '.');
00879 if (p)
00880 *p = '\0';
00881 }
00882
00883 scr = g_strdup_printf ("%s.%d", dname, number);
00884
00885 g_free (dname);
00886
00887 return scr;
00888 }
00889
00890 static gint
00891 ptrcmp (gconstpointer a, gconstpointer b)
00892 {
00893 if (a < b)
00894 return -1;
00895 else if (a > b)
00896 return 1;
00897 else
00898 return 0;
00899 }
00900
00901 static void
00902 listify_func (gpointer key, gpointer value, gpointer data)
00903 {
00904 GSList **listp;
00905
00906 listp = data;
00907
00908 *listp = g_slist_prepend (*listp, value);
00909 }
00910
00911 void
00912 meta_screen_foreach_window (MetaScreen *screen,
00913 MetaScreenWindowFunc func,
00914 gpointer data)
00915 {
00916 GSList *winlist;
00917 GSList *tmp;
00918
00919
00920
00921
00922
00923 winlist = NULL;
00924 g_hash_table_foreach (screen->display->window_ids,
00925 listify_func,
00926 &winlist);
00927
00928 winlist = g_slist_sort (winlist, ptrcmp);
00929
00930 tmp = winlist;
00931 while (tmp != NULL)
00932 {
00933
00934
00935
00936 if (tmp->next == NULL ||
00937 (tmp->next && tmp->next->data != tmp->data))
00938 {
00939 MetaWindow *window = tmp->data;
00940
00941 if (window->screen == screen)
00942 (* func) (screen, window, data);
00943 }
00944
00945 tmp = tmp->next;
00946 }
00947 g_slist_free (winlist);
00948 }
00949
00950 static void
00951 queue_draw (MetaScreen *screen, MetaWindow *window, gpointer data)
00952 {
00953 if (window->frame)
00954 meta_frame_queue_draw (window->frame);
00955 }
00956
00957 void
00958 meta_screen_queue_frame_redraws (MetaScreen *screen)
00959 {
00960 meta_screen_foreach_window (screen, queue_draw, NULL);
00961 }
00962
00963 static void
00964 queue_resize (MetaScreen *screen, MetaWindow *window, gpointer data)
00965 {
00966 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
00967 }
00968
00969 void
00970 meta_screen_queue_window_resizes (MetaScreen *screen)
00971 {
00972 meta_screen_foreach_window (screen, queue_resize, NULL);
00973 }
00974
00975 int
00976 meta_screen_get_n_workspaces (MetaScreen *screen)
00977 {
00978 return g_list_length (screen->workspaces);
00979 }
00980
00981 MetaWorkspace*
00982 meta_screen_get_workspace_by_index (MetaScreen *screen,
00983 int idx)
00984 {
00985 GList *tmp;
00986 int i;
00987
00988
00989 if (idx < 0)
00990 return NULL;
00991
00992 i = 0;
00993 tmp = screen->workspaces;
00994 while (tmp != NULL)
00995 {
00996 MetaWorkspace *w = tmp->data;
00997
00998 if (i == idx)
00999 return w;
01000
01001 ++i;
01002 tmp = tmp->next;
01003 }
01004
01005 return NULL;
01006 }
01007
01008 static void
01009 set_number_of_spaces_hint (MetaScreen *screen,
01010 int n_spaces)
01011 {
01012 unsigned long data[1];
01013
01014 if (screen->closing > 0)
01015 return;
01016
01017 data[0] = n_spaces;
01018
01019 meta_verbose ("Setting _NET_NUMBER_OF_DESKTOPS to %lu\n", data[0]);
01020
01021 meta_error_trap_push (screen->display);
01022 XChangeProperty (screen->display->xdisplay, screen->xroot,
01023 screen->display->atom__NET_NUMBER_OF_DESKTOPS,
01024 XA_CARDINAL,
01025 32, PropModeReplace, (guchar*) data, 1);
01026 meta_error_trap_pop (screen->display, FALSE);
01027 }
01028
01029 static void
01030 set_desktop_geometry_hint (MetaScreen *screen)
01031 {
01032 unsigned long data[2];
01033
01034 if (screen->closing > 0)
01035 return;
01036
01037 data[0] = screen->rect.width;
01038 data[1] = screen->rect.height;
01039
01040 meta_verbose ("Setting _NET_DESKTOP_GEOMETRY to %lu, %lu\n", data[0], data[1]);
01041
01042 meta_error_trap_push (screen->display);
01043 XChangeProperty (screen->display->xdisplay, screen->xroot,
01044 screen->display->atom__NET_DESKTOP_GEOMETRY,
01045 XA_CARDINAL,
01046 32, PropModeReplace, (guchar*) data, 2);
01047 meta_error_trap_pop (screen->display, FALSE);
01048 }
01049
01050 static void
01051 set_desktop_viewport_hint (MetaScreen *screen)
01052 {
01053 unsigned long data[2];
01054
01055 if (screen->closing > 0)
01056 return;
01057
01058
01059
01060
01061 data[0] = 0;
01062 data[1] = 0;
01063
01064 meta_verbose ("Setting _NET_DESKTOP_VIEWPORT to 0, 0\n");
01065
01066 meta_error_trap_push (screen->display);
01067 XChangeProperty (screen->display->xdisplay, screen->xroot,
01068 screen->display->atom__NET_DESKTOP_VIEWPORT,
01069 XA_CARDINAL,
01070 32, PropModeReplace, (guchar*) data, 2);
01071 meta_error_trap_pop (screen->display, FALSE);
01072 }
01073
01074 static void
01075 update_num_workspaces (MetaScreen *screen,
01076 guint32 timestamp)
01077 {
01078 int new_num;
01079 GList *tmp;
01080 int i;
01081 GList *extras;
01082 MetaWorkspace *last_remaining;
01083 gboolean need_change_space;
01084
01085 new_num = meta_prefs_get_num_workspaces ();
01086
01087 g_assert (new_num > 0);
01088
01089 last_remaining = NULL;
01090 extras = NULL;
01091 i = 0;
01092 tmp = screen->workspaces;
01093 while (tmp != NULL)
01094 {
01095 MetaWorkspace *w = tmp->data;
01096
01097 if (i >= new_num)
01098 extras = g_list_prepend (extras, w);
01099 else
01100 last_remaining = w;
01101
01102 ++i;
01103 tmp = tmp->next;
01104 }
01105
01106 g_assert (last_remaining);
01107
01108
01109
01110
01111
01112
01113
01114 need_change_space = FALSE;
01115 tmp = extras;
01116 while (tmp != NULL)
01117 {
01118 MetaWorkspace *w = tmp->data;
01119
01120 meta_workspace_relocate_windows (w, last_remaining);
01121
01122 if (w == screen->active_workspace)
01123 need_change_space = TRUE;
01124
01125 tmp = tmp->next;
01126 }
01127
01128 if (need_change_space)
01129 meta_workspace_activate (last_remaining, timestamp);
01130
01131
01132 tmp = extras;
01133 while (tmp != NULL)
01134 {
01135 MetaWorkspace *w = tmp->data;
01136
01137 g_assert (w->windows == NULL);
01138 meta_workspace_free (w);
01139
01140 tmp = tmp->next;
01141 }
01142
01143 g_list_free (extras);
01144
01145 while (i < new_num)
01146 {
01147 meta_workspace_new (screen);
01148 ++i;
01149 }
01150
01151 set_number_of_spaces_hint (screen, new_num);
01152
01153 meta_screen_queue_workarea_recalc (screen);
01154 }
01155
01156 static void
01157 update_focus_mode (MetaScreen *screen)
01158 {
01159 ;
01160 }
01161
01162 void
01163 meta_screen_set_cursor (MetaScreen *screen,
01164 MetaCursor cursor)
01165 {
01166 Cursor xcursor;
01167
01168 if (cursor == screen->current_cursor)
01169 return;
01170
01171 screen->current_cursor = cursor;
01172
01173 xcursor = meta_display_create_x_cursor (screen->display, cursor);
01174 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
01175 XFlush (screen->display->xdisplay);
01176 XFreeCursor (screen->display->xdisplay, xcursor);
01177 }
01178
01179 void
01180 meta_screen_update_cursor (MetaScreen *screen)
01181 {
01182 Cursor xcursor;
01183
01184 xcursor = meta_display_create_x_cursor (screen->display,
01185 screen->current_cursor);
01186 XDefineCursor (screen->display->xdisplay, screen->xroot, xcursor);
01187 XFlush (screen->display->xdisplay);
01188 XFreeCursor (screen->display->xdisplay, xcursor);
01189 }
01190
01191 #define MAX_PREVIEW_SIZE 150.0
01192
01193 static GdkPixbuf *
01194 get_window_pixbuf (MetaWindow *window,
01195 int *width,
01196 int *height)
01197 {
01198 Pixmap pmap;
01199 GdkPixbuf *pixbuf, *scaled;
01200 double ratio;
01201
01202 pmap = meta_compositor_get_window_pixmap (window->display->compositor,
01203 window);
01204 if (pmap == None)
01205 return NULL;
01206
01207 pixbuf = meta_ui_get_pixbuf_from_pixmap (pmap);
01208 if (pixbuf == NULL)
01209 return NULL;
01210
01211 *width = gdk_pixbuf_get_width (pixbuf);
01212 *height = gdk_pixbuf_get_height (pixbuf);
01213
01214
01215 if (*width > *height)
01216 {
01217 ratio = ((double) *width) / MAX_PREVIEW_SIZE;
01218 *width = (int) MAX_PREVIEW_SIZE;
01219 *height = (int) (((double) *height) / ratio);
01220 }
01221 else
01222 {
01223 ratio = ((double) *height) / MAX_PREVIEW_SIZE;
01224 *height = (int) MAX_PREVIEW_SIZE;
01225 *width = (int) (((double) *width) / ratio);
01226 }
01227
01228 scaled = gdk_pixbuf_scale_simple (pixbuf, *width, *height,
01229 GDK_INTERP_BILINEAR);
01230 g_object_unref (pixbuf);
01231 return scaled;
01232 }
01233
01234 void
01235 meta_screen_ensure_tab_popup (MetaScreen *screen,
01236 MetaTabList list_type,
01237 MetaTabShowType show_type)
01238 {
01239 MetaTabEntry *entries;
01240 GList *tab_list;
01241 GList *tmp;
01242 int len;
01243 int i;
01244
01245 if (screen->tab_popup)
01246 return;
01247
01248 tab_list = meta_display_get_tab_list (screen->display,
01249 list_type,
01250 screen,
01251 screen->active_workspace);
01252
01253 len = g_list_length (tab_list);
01254
01255 entries = g_new (MetaTabEntry, len + 1);
01256 entries[len].key = NULL;
01257 entries[len].title = NULL;
01258 entries[len].icon = NULL;
01259
01260 i = 0;
01261 tmp = tab_list;
01262 while (i < len)
01263 {
01264 MetaWindow *window;
01265 MetaRectangle r;
01266 GdkPixbuf *win_pixbuf;
01267 int width, height;
01268
01269 window = tmp->data;
01270
01271 entries[i].key = (MetaTabEntryKey) window->xwindow;
01272 entries[i].title = window->title;
01273
01274 win_pixbuf = get_window_pixbuf (window, &width, &height);
01275 if (win_pixbuf == NULL)
01276 entries[i].icon = g_object_ref (window->icon);
01277 else
01278 {
01279 int icon_width, icon_height, t_width, t_height;
01280 #define ICON_OFFSET 6
01281
01282 icon_width = gdk_pixbuf_get_width (window->icon);
01283 icon_height = gdk_pixbuf_get_height (window->icon);
01284
01285 t_width = width + ICON_OFFSET;
01286 t_height = height + ICON_OFFSET;
01287
01288 entries[i].icon = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
01289 t_width, t_height);
01290 gdk_pixbuf_fill (entries[i].icon, 0x00000000);
01291 gdk_pixbuf_copy_area (win_pixbuf, 0, 0, width, height,
01292 entries[i].icon, 0, 0);
01293 g_object_unref (win_pixbuf);
01294 gdk_pixbuf_composite (window->icon, entries[i].icon,
01295 t_width - icon_width, t_height - icon_height,
01296 icon_width, icon_height,
01297 t_width - icon_width, t_height - icon_height,
01298 1.0, 1.0, GDK_INTERP_BILINEAR, 255);
01299 }
01300
01301 entries[i].blank = FALSE;
01302 entries[i].hidden = !meta_window_showing_on_its_workspace (window);
01303 entries[i].demands_attention = window->wm_state_demands_attention;
01304
01305 if (show_type == META_TAB_SHOW_INSTANTLY ||
01306 !entries[i].hidden ||
01307 !meta_window_get_icon_geometry (window, &r))
01308 meta_window_get_outer_rect (window, &r);
01309
01310 entries[i].rect = r;
01311
01312
01313
01314
01315
01316
01317
01318 #define OUTLINE_WIDTH 5
01319
01320 if (!entries[i].hidden &&
01321 window->frame && window->frame->bottom_height > 0 &&
01322 window->frame->child_y >= window->frame->bottom_height)
01323 entries[i].inner_rect.y = window->frame->bottom_height;
01324 else
01325 entries[i].inner_rect.y = OUTLINE_WIDTH;
01326
01327
01328 if (!entries[i].hidden &&
01329 window->frame && window->frame->bottom_height != 0)
01330 entries[i].inner_rect.height = r.height
01331 - entries[i].inner_rect.y - window->frame->bottom_height;
01332 else
01333 entries[i].inner_rect.height = r.height
01334 - entries[i].inner_rect.y - OUTLINE_WIDTH;
01335
01336
01337 if (!entries[i].hidden && window->frame && window->frame->child_x != 0)
01338 entries[i].inner_rect.x = window->frame->child_x;
01339 else
01340 entries[i].inner_rect.x = OUTLINE_WIDTH;
01341
01342
01343 if (!entries[i].hidden &&
01344 window->frame && window->frame->right_width != 0)
01345 entries[i].inner_rect.width = r.width
01346 - entries[i].inner_rect.x - window->frame->right_width;
01347 else
01348 entries[i].inner_rect.width = r.width
01349 - entries[i].inner_rect.x - OUTLINE_WIDTH;
01350
01351 ++i;
01352 tmp = tmp->next;
01353 }
01354
01355 screen->tab_popup = meta_ui_tab_popup_new (entries,
01356 screen->number,
01357 len,
01358 5,
01359 TRUE);
01360
01361 for (i = 0; i < len; i++)
01362 g_object_unref (entries[i].icon);
01363
01364 g_free (entries);
01365
01366 g_list_free (tab_list);
01367
01368
01369 }
01370
01371 void
01372 meta_screen_ensure_workspace_popup (MetaScreen *screen)
01373 {
01374 MetaTabEntry *entries;
01375 int len;
01376 int i;
01377 MetaWorkspaceLayout layout;
01378 int n_workspaces;
01379 int current_workspace;
01380
01381 if (screen->tab_popup)
01382 return;
01383
01384 current_workspace = meta_workspace_index (screen->active_workspace);
01385 n_workspaces = meta_screen_get_n_workspaces (screen);
01386
01387 meta_screen_calc_workspace_layout (screen, n_workspaces,
01388 current_workspace, &layout);
01389
01390 len = layout.grid_area;
01391
01392 entries = g_new (MetaTabEntry, len + 1);
01393 entries[len].key = NULL;
01394 entries[len].title = NULL;
01395 entries[len].icon = NULL;
01396
01397 i = 0;
01398 while (i < len)
01399 {
01400 if (layout.grid[i] >= 0)
01401 {
01402 MetaWorkspace *workspace;
01403
01404 workspace = meta_screen_get_workspace_by_index (screen,
01405 layout.grid[i]);
01406
01407 entries[i].key = (MetaTabEntryKey) workspace;
01408 entries[i].title = meta_workspace_get_name (workspace);
01409 entries[i].icon = NULL;
01410 entries[i].blank = FALSE;
01411
01412 g_assert (entries[i].title != NULL);
01413 }
01414 else
01415 {
01416 entries[i].key = NULL;
01417 entries[i].title = NULL;
01418 entries[i].icon = NULL;
01419 entries[i].blank = TRUE;
01420 }
01421 entries[i].hidden = FALSE;
01422 entries[i].demands_attention = FALSE;
01423
01424 ++i;
01425 }
01426
01427 screen->tab_popup = meta_ui_tab_popup_new (entries,
01428 screen->number,
01429 len,
01430 layout.cols,
01431 FALSE);
01432
01433 g_free (entries);
01434 meta_screen_free_workspace_layout (&layout);
01435
01436
01437 }
01438
01439 MetaWindow*
01440 meta_screen_get_mouse_window (MetaScreen *screen,
01441 MetaWindow *not_this_one)
01442 {
01443 MetaWindow *window;
01444 Window root_return, child_return;
01445 int root_x_return, root_y_return;
01446 int win_x_return, win_y_return;
01447 unsigned int mask_return;
01448
01449 if (not_this_one)
01450 meta_topic (META_DEBUG_FOCUS,
01451 "Focusing mouse window excluding %s\n", not_this_one->desc);
01452
01453 meta_error_trap_push (screen->display);
01454 XQueryPointer (screen->display->xdisplay,
01455 screen->xroot,
01456 &root_return,
01457 &child_return,
01458 &root_x_return,
01459 &root_y_return,
01460 &win_x_return,
01461 &win_y_return,
01462 &mask_return);
01463 meta_error_trap_pop (screen->display, TRUE);
01464
01465 window = meta_stack_get_default_focus_window_at_point (screen->stack,
01466 screen->active_workspace,
01467 not_this_one,
01468 root_x_return,
01469 root_y_return);
01470
01471 return window;
01472 }
01473
01474 const MetaXineramaScreenInfo*
01475 meta_screen_get_xinerama_for_rect (MetaScreen *screen,
01476 MetaRectangle *rect)
01477 {
01478 int i;
01479 int best_xinerama, xinerama_score;
01480
01481 if (screen->n_xinerama_infos == 1)
01482 return &screen->xinerama_infos[0];
01483
01484 best_xinerama = 0;
01485 xinerama_score = 0;
01486
01487 for (i = 0; i < screen->n_xinerama_infos; i++)
01488 {
01489 MetaRectangle dest;
01490 if (meta_rectangle_intersect (&screen->xinerama_infos[i].rect,
01491 rect,
01492 &dest))
01493 {
01494 int cur = meta_rectangle_area (&dest);
01495 if (cur > xinerama_score)
01496 {
01497 xinerama_score = cur;
01498 best_xinerama = i;
01499 }
01500 }
01501 }
01502
01503 return &screen->xinerama_infos[best_xinerama];
01504 }
01505
01506 const MetaXineramaScreenInfo*
01507 meta_screen_get_xinerama_for_window (MetaScreen *screen,
01508 MetaWindow *window)
01509 {
01510 MetaRectangle window_rect;
01511
01512 meta_window_get_outer_rect (window, &window_rect);
01513
01514 return meta_screen_get_xinerama_for_rect (screen, &window_rect);
01515 }
01516
01517 const MetaXineramaScreenInfo*
01518 meta_screen_get_xinerama_neighbor (MetaScreen *screen,
01519 int which_xinerama,
01520 MetaScreenDirection direction)
01521 {
01522 MetaXineramaScreenInfo* input = screen->xinerama_infos + which_xinerama;
01523 MetaXineramaScreenInfo* current;
01524 int i;
01525
01526 for (i = 0; i < screen->n_xinerama_infos; i++)
01527 {
01528 current = screen->xinerama_infos + i;
01529
01530 if ((direction == META_SCREEN_RIGHT &&
01531 current->rect.x == input->rect.x + input->rect.width &&
01532 meta_rectangle_vert_overlap(¤t->rect, &input->rect)) ||
01533 (direction == META_SCREEN_LEFT &&
01534 input->rect.x == current->rect.x + current->rect.width &&
01535 meta_rectangle_vert_overlap(¤t->rect, &input->rect)) ||
01536 (direction == META_SCREEN_UP &&
01537 input->rect.y == current->rect.y + current->rect.height &&
01538 meta_rectangle_horiz_overlap(¤t->rect, &input->rect)) ||
01539 (direction == META_SCREEN_DOWN &&
01540 current->rect.y == input->rect.y + input->rect.height &&
01541 meta_rectangle_horiz_overlap(¤t->rect, &input->rect)))
01542 {
01543 return current;
01544 }
01545 }
01546
01547 return NULL;
01548 }
01549
01550 void
01551 meta_screen_get_natural_xinerama_list (MetaScreen *screen,
01552 int** xineramas_list,
01553 int* n_xineramas)
01554 {
01555 const MetaXineramaScreenInfo* current;
01556 const MetaXineramaScreenInfo* tmp;
01557 GQueue* xinerama_queue;
01558 int* visited;
01559 int cur = 0;
01560 int i;
01561
01562 *n_xineramas = screen->n_xinerama_infos;
01563 *xineramas_list = g_new (int, screen->n_xinerama_infos);
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573 visited = g_new (int, screen->n_xinerama_infos);
01574 for (i = 0; i < screen->n_xinerama_infos; i++)
01575 {
01576 visited[i] = FALSE;
01577 }
01578
01579 current = meta_screen_get_current_xinerama (screen);
01580 xinerama_queue = g_queue_new ();
01581 g_queue_push_tail (xinerama_queue, (gpointer) current);
01582 visited[current->number] = TRUE;
01583
01584 while (!g_queue_is_empty (xinerama_queue))
01585 {
01586 current = (const MetaXineramaScreenInfo*)
01587 g_queue_pop_head (xinerama_queue);
01588
01589 (*xineramas_list)[cur++] = current->number;
01590
01591
01592 tmp = meta_screen_get_xinerama_neighbor (screen,
01593 current->number,
01594 META_SCREEN_LEFT);
01595 if (tmp && !visited[tmp->number])
01596 {
01597 g_queue_push_tail (xinerama_queue,
01598 (MetaXineramaScreenInfo*) tmp);
01599 visited[tmp->number] = TRUE;
01600 }
01601 tmp = meta_screen_get_xinerama_neighbor (screen,
01602 current->number,
01603 META_SCREEN_RIGHT);
01604 if (tmp && !visited[tmp->number])
01605 {
01606 g_queue_push_tail (xinerama_queue,
01607 (MetaXineramaScreenInfo*) tmp);
01608 visited[tmp->number] = TRUE;
01609 }
01610 tmp = meta_screen_get_xinerama_neighbor (screen,
01611 current->number,
01612 META_SCREEN_UP);
01613 if (tmp && !visited[tmp->number])
01614 {
01615 g_queue_push_tail (xinerama_queue,
01616 (MetaXineramaScreenInfo*) tmp);
01617 visited[tmp->number] = TRUE;
01618 }
01619 tmp = meta_screen_get_xinerama_neighbor (screen,
01620 current->number,
01621 META_SCREEN_DOWN);
01622 if (tmp && !visited[tmp->number])
01623 {
01624 g_queue_push_tail (xinerama_queue,
01625 (MetaXineramaScreenInfo*) tmp);
01626 visited[tmp->number] = TRUE;
01627 }
01628 }
01629
01630
01631
01632
01633 for (i = 0; i < screen->n_xinerama_infos; i++)
01634 {
01635 if (visited[i] == FALSE)
01636 {
01637 (*xineramas_list)[cur++] = i;
01638 }
01639 }
01640
01641 g_free (visited);
01642 g_queue_free (xinerama_queue);
01643 }
01644
01645 const MetaXineramaScreenInfo*
01646 meta_screen_get_current_xinerama (MetaScreen *screen)
01647 {
01648 if (screen->n_xinerama_infos == 1)
01649 return &screen->xinerama_infos[0];
01650
01651
01652
01653
01654 if (screen->display->xinerama_cache_invalidated)
01655 {
01656 Window root_return, child_return;
01657 int win_x_return, win_y_return;
01658 unsigned int mask_return;
01659 int i;
01660 MetaRectangle pointer_position;
01661
01662 screen->display->xinerama_cache_invalidated = FALSE;
01663
01664 pointer_position.width = pointer_position.height = 1;
01665 XQueryPointer (screen->display->xdisplay,
01666 screen->xroot,
01667 &root_return,
01668 &child_return,
01669 &pointer_position.x,
01670 &pointer_position.y,
01671 &win_x_return,
01672 &win_y_return,
01673 &mask_return);
01674
01675 screen->last_xinerama_index = 0;
01676 for (i = 0; i < screen->n_xinerama_infos; i++)
01677 {
01678 if (meta_rectangle_contains_rect (&screen->xinerama_infos[i].rect,
01679 &pointer_position))
01680 {
01681 screen->last_xinerama_index = i;
01682 break;
01683 }
01684 }
01685
01686 meta_topic (META_DEBUG_XINERAMA,
01687 "Rechecked current Xinerama, now %d\n",
01688 screen->last_xinerama_index);
01689 }
01690
01691 return &screen->xinerama_infos[screen->last_xinerama_index];
01692 }
01693
01694 #define _NET_WM_ORIENTATION_HORZ 0
01695 #define _NET_WM_ORIENTATION_VERT 1
01696
01697 #define _NET_WM_TOPLEFT 0
01698 #define _NET_WM_TOPRIGHT 1
01699 #define _NET_WM_BOTTOMRIGHT 2
01700 #define _NET_WM_BOTTOMLEFT 3
01701
01702 void
01703 meta_screen_update_workspace_layout (MetaScreen *screen)
01704 {
01705 gulong *list;
01706 int n_items;
01707
01708 list = NULL;
01709 n_items = 0;
01710
01711 if (meta_prop_get_cardinal_list (screen->display,
01712 screen->xroot,
01713 screen->display->atom__NET_DESKTOP_LAYOUT,
01714 &list, &n_items))
01715 {
01716 if (n_items == 3 || n_items == 4)
01717 {
01718 int cols, rows;
01719
01720 switch (list[0])
01721 {
01722 case _NET_WM_ORIENTATION_HORZ:
01723 screen->vertical_workspaces = FALSE;
01724 break;
01725 case _NET_WM_ORIENTATION_VERT:
01726 screen->vertical_workspaces = TRUE;
01727 break;
01728 default:
01729 meta_warning ("Someone set a weird orientation in _NET_DESKTOP_LAYOUT\n");
01730 break;
01731 }
01732
01733 cols = list[1];
01734 rows = list[2];
01735
01736 if (rows <= 0 && cols <= 0)
01737 {
01738 meta_warning ("Columns = %d rows = %d in _NET_DESKTOP_LAYOUT makes no sense\n", rows, cols);
01739 }
01740 else
01741 {
01742 if (rows > 0)
01743 screen->rows_of_workspaces = rows;
01744 else
01745 screen->rows_of_workspaces = -1;
01746
01747 if (cols > 0)
01748 screen->columns_of_workspaces = cols;
01749 else
01750 screen->columns_of_workspaces = -1;
01751 }
01752
01753 if (n_items == 4)
01754 {
01755 switch (list[3])
01756 {
01757 case _NET_WM_TOPLEFT:
01758 screen->starting_corner = META_SCREEN_TOPLEFT;
01759 break;
01760 case _NET_WM_TOPRIGHT:
01761 screen->starting_corner = META_SCREEN_TOPRIGHT;
01762 break;
01763 case _NET_WM_BOTTOMRIGHT:
01764 screen->starting_corner = META_SCREEN_BOTTOMRIGHT;
01765 break;
01766 case _NET_WM_BOTTOMLEFT:
01767 screen->starting_corner = META_SCREEN_BOTTOMLEFT;
01768 break;
01769 default:
01770 meta_warning ("Someone set a weird starting corner in _NET_DESKTOP_LAYOUT\n");
01771 break;
01772 }
01773 }
01774 else
01775 screen->starting_corner = META_SCREEN_TOPLEFT;
01776 }
01777 else
01778 {
01779 meta_warning ("Someone set _NET_DESKTOP_LAYOUT to %d integers instead of 4 "
01780 "(3 is accepted for backwards compat)\n", n_items);
01781 }
01782
01783 meta_XFree (list);
01784 }
01785
01786 meta_verbose ("Workspace layout rows = %d cols = %d orientation = %d starting corner = %u\n",
01787 screen->rows_of_workspaces,
01788 screen->columns_of_workspaces,
01789 screen->vertical_workspaces,
01790 screen->starting_corner);
01791 }
01792
01793 static void
01794 set_workspace_names (MetaScreen *screen)
01795 {
01796
01797
01798
01799
01800 GString *flattened;
01801 int i;
01802 int n_spaces;
01803
01804
01805 n_spaces = meta_screen_get_n_workspaces (screen);
01806 flattened = g_string_new ("");
01807 i = 0;
01808 while (i < n_spaces)
01809 {
01810 const char *name;
01811
01812 name = meta_prefs_get_workspace_name (i);
01813
01814 if (name)
01815 g_string_append_len (flattened, name,
01816 strlen (name) + 1);
01817 else
01818 g_string_append_len (flattened, "", 1);
01819
01820 ++i;
01821 }
01822
01823 meta_error_trap_push (screen->display);
01824 XChangeProperty (screen->display->xdisplay,
01825 screen->xroot,
01826 screen->display->atom__NET_DESKTOP_NAMES,
01827 screen->display->atom_UTF8_STRING,
01828 8, PropModeReplace,
01829 (unsigned char *)flattened->str, flattened->len);
01830 meta_error_trap_pop (screen->display, FALSE);
01831
01832 g_string_free (flattened, TRUE);
01833 }
01834
01835 void
01836 meta_screen_update_workspace_names (MetaScreen *screen)
01837 {
01838 char **names;
01839 int n_names;
01840 int i;
01841
01842
01843
01844
01845
01846 names = NULL;
01847 n_names = 0;
01848 if (!meta_prop_get_utf8_list (screen->display,
01849 screen->xroot,
01850 screen->display->atom__NET_DESKTOP_NAMES,
01851 &names, &n_names))
01852 {
01853 meta_verbose ("Failed to get workspace names from root window %d\n",
01854 screen->number);
01855 return;
01856 }
01857
01858 i = 0;
01859 while (i < n_names)
01860 {
01861 meta_topic (META_DEBUG_PREFS,
01862 "Setting workspace %d name to \"%s\" due to _NET_DESKTOP_NAMES change\n",
01863 i, names[i] ? names[i] : "null");
01864 meta_prefs_change_workspace_name (i, names[i]);
01865
01866 ++i;
01867 }
01868
01869 g_strfreev (names);
01870 }
01871
01872 Window
01873 meta_create_offscreen_window (Display *xdisplay,
01874 Window parent,
01875 long valuemask)
01876 {
01877 XSetWindowAttributes attrs;
01878
01879
01880
01881
01882
01883 attrs.override_redirect = True;
01884 attrs.event_mask = valuemask;
01885
01886 return XCreateWindow (xdisplay,
01887 parent,
01888 -100, -100, 1, 1,
01889 0,
01890 CopyFromParent,
01891 CopyFromParent,
01892 (Visual *)CopyFromParent,
01893 CWOverrideRedirect | CWEventMask,
01894 &attrs);
01895 }
01896
01897 static void
01898 set_work_area_hint (MetaScreen *screen)
01899 {
01900 int num_workspaces;
01901 GList *tmp_list;
01902 unsigned long *data, *tmp;
01903 MetaRectangle area;
01904
01905 num_workspaces = meta_screen_get_n_workspaces (screen);
01906 data = g_new (unsigned long, num_workspaces * 4);
01907 tmp_list = screen->workspaces;
01908 tmp = data;
01909
01910 while (tmp_list != NULL)
01911 {
01912 MetaWorkspace *workspace = tmp_list->data;
01913
01914 if (workspace->screen == screen)
01915 {
01916 meta_workspace_get_work_area_all_xineramas (workspace, &area);
01917 tmp[0] = area.x;
01918 tmp[1] = area.y;
01919 tmp[2] = area.width;
01920 tmp[3] = area.height;
01921
01922 tmp += 4;
01923 }
01924
01925 tmp_list = tmp_list->next;
01926 }
01927
01928 meta_error_trap_push (screen->display);
01929 XChangeProperty (screen->display->xdisplay, screen->xroot,
01930 screen->display->atom__NET_WORKAREA,
01931 XA_CARDINAL, 32, PropModeReplace,
01932 (guchar*) data, num_workspaces*4);
01933 g_free (data);
01934 meta_error_trap_pop (screen->display, FALSE);
01935 }
01936
01937 static gboolean
01938 set_work_area_idle_func (MetaScreen *screen)
01939 {
01940 meta_topic (META_DEBUG_WORKAREA,
01941 "Running work area idle function\n");
01942
01943 screen->work_area_idle = 0;
01944
01945 set_work_area_hint (screen);
01946
01947 return FALSE;
01948 }
01949
01950 void
01951 meta_screen_queue_workarea_recalc (MetaScreen *screen)
01952 {
01953
01954 if (screen->work_area_idle == 0)
01955 {
01956 meta_topic (META_DEBUG_WORKAREA,
01957 "Adding work area hint idle function\n");
01958 screen->work_area_idle =
01959 g_idle_add_full (META_PRIORITY_WORK_AREA_HINT,
01960 (GSourceFunc) set_work_area_idle_func,
01961 screen,
01962 NULL);
01963 }
01964 }
01965
01966
01967 #ifdef WITH_VERBOSE_MODE
01968 static char *
01969 meta_screen_corner_to_string (MetaScreenCorner corner)
01970 {
01971 switch (corner)
01972 {
01973 case META_SCREEN_TOPLEFT:
01974 return "TopLeft";
01975 case META_SCREEN_TOPRIGHT:
01976 return "TopRight";
01977 case META_SCREEN_BOTTOMLEFT:
01978 return "BottomLeft";
01979 case META_SCREEN_BOTTOMRIGHT:
01980 return "BottomRight";
01981 }
01982
01983 return "Unknown";
01984 }
01985 #endif
01986
01987 void
01988 meta_screen_calc_workspace_layout (MetaScreen *screen,
01989 int num_workspaces,
01990 int current_space,
01991 MetaWorkspaceLayout *layout)
01992 {
01993 int rows, cols;
01994 int grid_area;
01995 int *grid;
01996 int i, r, c;
01997 int current_row, current_col;
01998
01999 rows = screen->rows_of_workspaces;
02000 cols = screen->columns_of_workspaces;
02001 if (rows <= 0 && cols <= 0)
02002 cols = num_workspaces;
02003
02004 if (rows <= 0)
02005 rows = num_workspaces / cols + ((num_workspaces % cols) > 0 ? 1 : 0);
02006 if (cols <= 0)
02007 cols = num_workspaces / rows + ((num_workspaces % rows) > 0 ? 1 : 0);
02008
02009
02010 if (rows < 1)
02011 rows = 1;
02012 if (cols < 1)
02013 cols = 1;
02014
02015 g_assert (rows != 0 && cols != 0);
02016
02017 grid_area = rows * cols;
02018
02019 meta_verbose ("Getting layout rows = %d cols = %d current = %d "
02020 "num_spaces = %d vertical = %s corner = %s\n",
02021 rows, cols, current_space, num_workspaces,
02022 screen->vertical_workspaces ? "(true)" : "(false)",
02023 meta_screen_corner_to_string (screen->starting_corner));
02024
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038
02039
02040
02041
02042
02043
02044
02045
02046
02047
02048
02049
02050
02051
02052
02053
02054
02055
02056
02057
02058 grid = g_new (int, grid_area);
02059
02060 current_row = -1;
02061 current_col = -1;
02062 i = 0;
02063
02064 switch (screen->starting_corner)
02065 {
02066 case META_SCREEN_TOPLEFT:
02067 if (screen->vertical_workspaces)
02068 {
02069 c = 0;
02070 while (c < cols)
02071 {
02072 r = 0;
02073 while (r < rows)
02074 {
02075 grid[r*cols+c] = i;
02076 ++i;
02077 ++r;
02078 }
02079 ++c;
02080 }
02081 }
02082 else
02083 {
02084 r = 0;
02085 while (r < rows)
02086 {
02087 c = 0;
02088 while (c < cols)
02089 {
02090 grid[r*cols+c] = i;
02091 ++i;
02092 ++c;
02093 }
02094 ++r;
02095 }
02096 }
02097 break;
02098 case META_SCREEN_TOPRIGHT:
02099 if (screen->vertical_workspaces)
02100 {
02101 c = cols - 1;
02102 while (c >= 0)
02103 {
02104 r = 0;
02105 while (r < rows)
02106 {
02107 grid[r*cols+c] = i;
02108 ++i;
02109 ++r;
02110 }
02111 --c;
02112 }
02113 }
02114 else
02115 {
02116 r = 0;
02117 while (r < rows)
02118 {
02119 c = cols - 1;
02120 while (c >= 0)
02121 {
02122 grid[r*cols+c] = i;
02123 ++i;
02124 --c;
02125 }
02126 ++r;
02127 }
02128 }
02129 break;
02130 case META_SCREEN_BOTTOMLEFT:
02131 if (screen->vertical_workspaces)
02132 {
02133 c = 0;
02134 while (c < cols)
02135 {
02136 r = rows - 1;
02137 while (r >= 0)
02138 {
02139 grid[r*cols+c] = i;
02140 ++i;
02141 --r;
02142 }
02143 ++c;
02144 }
02145 }
02146 else
02147 {
02148 r = rows - 1;
02149 while (r >= 0)
02150 {
02151 c = 0;
02152 while (c < cols)
02153 {
02154 grid[r*cols+c] = i;
02155 ++i;
02156 ++c;
02157 }
02158 --r;
02159 }
02160 }
02161 break;
02162 case META_SCREEN_BOTTOMRIGHT:
02163 if (screen->vertical_workspaces)
02164 {
02165 c = cols - 1;
02166 while (c >= 0)
02167 {
02168 r = rows - 1;
02169 while (r >= 0)
02170 {
02171 grid[r*cols+c] = i;
02172 ++i;
02173 --r;
02174 }
02175 --c;
02176 }
02177 }
02178 else
02179 {
02180 r = rows - 1;
02181 while (r >= 0)
02182 {
02183 c = cols - 1;
02184 while (c >= 0)
02185 {
02186 grid[r*cols+c] = i;
02187 ++i;
02188 --c;
02189 }
02190 --r;
02191 }
02192 }
02193 break;
02194 }
02195
02196 if (i != grid_area)
02197 meta_bug ("did not fill in the whole workspace grid in %s (%d filled)\n",
02198 G_STRFUNC, i);
02199
02200 current_row = 0;
02201 current_col = 0;
02202 r = 0;
02203 while (r < rows)
02204 {
02205 c = 0;
02206 while (c < cols)
02207 {
02208 if (grid[r*cols+c] == current_space)
02209 {
02210 current_row = r;
02211 current_col = c;
02212 }
02213 else if (grid[r*cols+c] >= num_workspaces)
02214 {
02215
02216 grid[r*cols+c] = -1;
02217 }
02218 ++c;
02219 }
02220 ++r;
02221 }
02222
02223 layout->rows = rows;
02224 layout->cols = cols;
02225 layout->grid = grid;
02226 layout->grid_area = grid_area;
02227 layout->current_row = current_row;
02228 layout->current_col = current_col;
02229
02230 #ifdef WITH_VERBOSE_MODE
02231 if (meta_is_verbose ())
02232 {
02233 r = 0;
02234 while (r < layout->rows)
02235 {
02236 meta_verbose (" ");
02237 meta_push_no_msg_prefix ();
02238 c = 0;
02239 while (c < layout->cols)
02240 {
02241 if (r == layout->current_row &&
02242 c == layout->current_col)
02243 meta_verbose ("*%2d ", layout->grid[r*layout->cols+c]);
02244 else
02245 meta_verbose ("%3d ", layout->grid[r*layout->cols+c]);
02246 ++c;
02247 }
02248 meta_verbose ("\n");
02249 meta_pop_no_msg_prefix ();
02250 ++r;
02251 }
02252 }
02253 #endif
02254 }
02255
02256 void
02257 meta_screen_free_workspace_layout (MetaWorkspaceLayout *layout)
02258 {
02259 g_free (layout->grid);
02260 }
02261
02262 static void
02263 meta_screen_resize_func (MetaScreen *screen,
02264 MetaWindow *window,
02265 void *user_data)
02266 {
02267 if (window->struts)
02268 {
02269 meta_window_update_struts (window);
02270 }
02271 meta_window_queue (window, META_QUEUE_MOVE_RESIZE);
02272
02273 meta_window_recalc_features (window);
02274 }
02275
02276 void
02277 meta_screen_resize (MetaScreen *screen,
02278 int width,
02279 int height)
02280 {
02281 screen->rect.width = width;
02282 screen->rect.height = height;
02283
02284 reload_xinerama_infos (screen);
02285 set_desktop_geometry_hint (screen);
02286
02287
02288 meta_screen_foreach_window (screen, meta_screen_resize_func, 0);
02289 }
02290
02291 void
02292 meta_screen_update_showing_desktop_hint (MetaScreen *screen)
02293 {
02294 unsigned long data[1];
02295
02296 data[0] = screen->active_workspace->showing_desktop ? 1 : 0;
02297
02298 meta_error_trap_push (screen->display);
02299 XChangeProperty (screen->display->xdisplay, screen->xroot,
02300 screen->display->atom__NET_SHOWING_DESKTOP,
02301 XA_CARDINAL,
02302 32, PropModeReplace, (guchar*) data, 1);
02303 meta_error_trap_pop (screen->display, FALSE);
02304 }
02305
02306 static void
02307 queue_windows_showing (MetaScreen *screen)
02308 {
02309 GSList *windows;
02310 GSList *tmp;
02311
02312
02313
02314
02315
02316 windows = meta_display_list_windows (screen->display);
02317
02318 tmp = windows;
02319 while (tmp != NULL)
02320 {
02321 MetaWindow *w = tmp->data;
02322
02323 if (w->screen == screen)
02324 meta_window_queue (w, META_QUEUE_CALC_SHOWING);
02325
02326 tmp = tmp->next;
02327 }
02328
02329 g_slist_free (windows);
02330 }
02331
02332 void
02333 meta_screen_minimize_all_on_active_workspace_except (MetaScreen *screen,
02334 MetaWindow *keep)
02335 {
02336 GList *windows;
02337 GList *tmp;
02338
02339 windows = screen->active_workspace->windows;
02340
02341 tmp = windows;
02342 while (tmp != NULL)
02343 {
02344 MetaWindow *w = tmp->data;
02345
02346 if (w->screen == screen &&
02347 w->has_minimize_func &&
02348 w != keep)
02349 meta_window_minimize (w);
02350
02351 tmp = tmp->next;
02352 }
02353 }
02354
02355 void
02356 meta_screen_show_desktop (MetaScreen *screen,
02357 guint32 timestamp)
02358 {
02359 GList *windows;
02360
02361 if (screen->active_workspace->showing_desktop)
02362 return;
02363
02364 screen->active_workspace->showing_desktop = TRUE;
02365
02366 queue_windows_showing (screen);
02367
02368
02369
02370
02371 windows = screen->active_workspace->mru_list;
02372 while (windows != NULL)
02373 {
02374 MetaWindow *w = windows->data;
02375
02376 if (w->screen == screen &&
02377 w->type == META_WINDOW_DESKTOP)
02378 {
02379 meta_window_focus (w, timestamp);
02380 break;
02381 }
02382
02383 windows = windows->next;
02384 }
02385
02386
02387 meta_screen_update_showing_desktop_hint (screen);
02388 }
02389
02390 void
02391 meta_screen_unshow_desktop (MetaScreen *screen)
02392 {
02393 if (!screen->active_workspace->showing_desktop)
02394 return;
02395
02396 screen->active_workspace->showing_desktop = FALSE;
02397
02398 queue_windows_showing (screen);
02399
02400 meta_screen_update_showing_desktop_hint (screen);
02401 }
02402
02403
02404 #ifdef HAVE_STARTUP_NOTIFICATION
02405 static gboolean startup_sequence_timeout (void *data);
02406
02407 static void
02408 update_startup_feedback (MetaScreen *screen)
02409 {
02410 if (screen->startup_sequences != NULL)
02411 {
02412 meta_topic (META_DEBUG_STARTUP,
02413 "Setting busy cursor\n");
02414 meta_screen_set_cursor (screen, META_CURSOR_BUSY);
02415 }
02416 else
02417 {
02418 meta_topic (META_DEBUG_STARTUP,
02419 "Setting default cursor\n");
02420 meta_screen_set_cursor (screen, META_CURSOR_DEFAULT);
02421 }
02422 }
02423
02424 static void
02425 add_sequence (MetaScreen *screen,
02426 SnStartupSequence *sequence)
02427 {
02428 meta_topic (META_DEBUG_STARTUP,
02429 "Adding sequence %s\n",
02430 sn_startup_sequence_get_id (sequence));
02431 sn_startup_sequence_ref (sequence);
02432 screen->startup_sequences = g_slist_prepend (screen->startup_sequences,
02433 sequence);
02434
02435
02436
02437
02438 if (screen->startup_sequence_timeout == 0)
02439 screen->startup_sequence_timeout = g_timeout_add (1000,
02440 startup_sequence_timeout,
02441 screen);
02442
02443 update_startup_feedback (screen);
02444 }
02445
02446 static void
02447 remove_sequence (MetaScreen *screen,
02448 SnStartupSequence *sequence)
02449 {
02450 meta_topic (META_DEBUG_STARTUP,
02451 "Removing sequence %s\n",
02452 sn_startup_sequence_get_id (sequence));
02453
02454 screen->startup_sequences = g_slist_remove (screen->startup_sequences,
02455 sequence);
02456 sn_startup_sequence_unref (sequence);
02457
02458 if (screen->startup_sequences == NULL &&
02459 screen->startup_sequence_timeout != 0)
02460 {
02461 g_source_remove (screen->startup_sequence_timeout);
02462 screen->startup_sequence_timeout = 0;
02463 }
02464
02465 update_startup_feedback (screen);
02466 }
02467
02468 typedef struct
02469 {
02470 GSList *list;
02471 GTimeVal now;
02472 } CollectTimedOutData;
02473
02474
02475
02476
02477
02478
02479 #define STARTUP_TIMEOUT 15000
02480
02481 static void
02482 collect_timed_out_foreach (void *element,
02483 void *data)
02484 {
02485 CollectTimedOutData *ctod = data;
02486 SnStartupSequence *sequence = element;
02487 long tv_sec, tv_usec;
02488 double elapsed;
02489
02490 sn_startup_sequence_get_last_active_time (sequence, &tv_sec, &tv_usec);
02491
02492 elapsed =
02493 ((((double)ctod->now.tv_sec - tv_sec) * G_USEC_PER_SEC +
02494 (ctod->now.tv_usec - tv_usec))) / 1000.0;
02495
02496 meta_topic (META_DEBUG_STARTUP,
02497 "Sequence used %g seconds vs. %g max: %s\n",
02498 elapsed, (double) STARTUP_TIMEOUT,
02499 sn_startup_sequence_get_id (sequence));
02500
02501 if (elapsed > STARTUP_TIMEOUT)
02502 ctod->list = g_slist_prepend (ctod->list, sequence);
02503 }
02504
02505 static gboolean
02506 startup_sequence_timeout (void *data)
02507 {
02508 MetaScreen *screen = data;
02509 CollectTimedOutData ctod;
02510 GSList *tmp;
02511
02512 ctod.list = NULL;
02513 g_get_current_time (&ctod.now);
02514 g_slist_foreach (screen->startup_sequences,
02515 collect_timed_out_foreach,
02516 &ctod);
02517
02518 tmp = ctod.list;
02519 while (tmp != NULL)
02520 {
02521 SnStartupSequence *sequence = tmp->data;
02522
02523 meta_topic (META_DEBUG_STARTUP,
02524 "Timed out sequence %s\n",
02525 sn_startup_sequence_get_id (sequence));
02526
02527 sn_startup_sequence_complete (sequence);
02528
02529 tmp = tmp->next;
02530 }
02531
02532 g_slist_free (ctod.list);
02533
02534 if (screen->startup_sequences != NULL)
02535 {
02536 return TRUE;
02537 }
02538 else
02539 {
02540
02541 screen->startup_sequence_timeout = 0;
02542 return FALSE;
02543 }
02544 }
02545
02546 static void
02547 meta_screen_sn_event (SnMonitorEvent *event,
02548 void *user_data)
02549 {
02550 MetaScreen *screen;
02551 SnStartupSequence *sequence;
02552
02553 screen = user_data;
02554
02555 sequence = sn_monitor_event_get_startup_sequence (event);
02556
02557 switch (sn_monitor_event_get_type (event))
02558 {
02559 case SN_MONITOR_EVENT_INITIATED:
02560 {
02561 const char *wmclass;
02562
02563 wmclass = sn_startup_sequence_get_wmclass (sequence);
02564
02565 meta_topic (META_DEBUG_STARTUP,
02566 "Received startup initiated for %s wmclass %s\n",
02567 sn_startup_sequence_get_id (sequence),
02568 wmclass ? wmclass : "(unset)");
02569 add_sequence (screen, sequence);
02570 }
02571 break;
02572
02573 case SN_MONITOR_EVENT_COMPLETED:
02574 {
02575 meta_topic (META_DEBUG_STARTUP,
02576 "Received startup completed for %s\n",
02577 sn_startup_sequence_get_id (sequence));
02578 remove_sequence (screen,
02579 sn_monitor_event_get_startup_sequence (event));
02580 }
02581 break;
02582
02583 case SN_MONITOR_EVENT_CHANGED:
02584 meta_topic (META_DEBUG_STARTUP,
02585 "Received startup changed for %s\n",
02586 sn_startup_sequence_get_id (sequence));
02587 break;
02588
02589 case SN_MONITOR_EVENT_CANCELED:
02590 meta_topic (META_DEBUG_STARTUP,
02591 "Received startup canceled for %s\n",
02592 sn_startup_sequence_get_id (sequence));
02593 break;
02594 }
02595 }
02596 #endif
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606 gboolean
02607 meta_screen_apply_startup_properties (MetaScreen *screen,
02608 MetaWindow *window)
02609 {
02610 #ifdef HAVE_STARTUP_NOTIFICATION
02611 const char *startup_id;
02612 GSList *tmp;
02613 SnStartupSequence *sequence;
02614
02615
02616 startup_id = meta_window_get_startup_id (window);
02617
02618 meta_topic (META_DEBUG_STARTUP,
02619 "Applying startup props to %s id \"%s\"\n",
02620 window->desc,
02621 startup_id ? startup_id : "(none)");
02622
02623 sequence = NULL;
02624 if (startup_id == NULL)
02625 {
02626
02627
02628
02629
02630 tmp = screen->startup_sequences;
02631 while (tmp != NULL)
02632 {
02633 const char *wmclass;
02634
02635 wmclass = sn_startup_sequence_get_wmclass (tmp->data);
02636
02637 if (wmclass != NULL &&
02638 ((window->res_class &&
02639 strcmp (wmclass, window->res_class) == 0) ||
02640 (window->res_name &&
02641 strcmp (wmclass, window->res_name) == 0)))
02642 {
02643 sequence = tmp->data;
02644
02645 g_assert (window->startup_id == NULL);
02646 window->startup_id = g_strdup (sn_startup_sequence_get_id (sequence));
02647 startup_id = window->startup_id;
02648
02649 meta_topic (META_DEBUG_STARTUP,
02650 "Ending legacy sequence %s due to window %s\n",
02651 sn_startup_sequence_get_id (sequence),
02652 window->desc);
02653
02654 sn_startup_sequence_complete (sequence);
02655 break;
02656 }
02657
02658 tmp = tmp->next;
02659 }
02660 }
02661
02662
02663 if (startup_id == NULL)
02664 return FALSE;
02665
02666
02667
02668
02669
02670 if (sequence == NULL)
02671 {
02672 tmp = screen->startup_sequences;
02673 while (tmp != NULL)
02674 {
02675 const char *id;
02676
02677 id = sn_startup_sequence_get_id (tmp->data);
02678
02679 if (strcmp (id, startup_id) == 0)
02680 {
02681 sequence = tmp->data;
02682 break;
02683 }
02684
02685 tmp = tmp->next;
02686 }
02687 }
02688
02689 if (sequence != NULL)
02690 {
02691 gboolean changed_something = FALSE;
02692
02693 meta_topic (META_DEBUG_STARTUP,
02694 "Found startup sequence for window %s ID \"%s\"\n",
02695 window->desc, startup_id);
02696
02697 if (!window->initial_workspace_set)
02698 {
02699 int space = sn_startup_sequence_get_workspace (sequence);
02700 if (space >= 0)
02701 {
02702 meta_topic (META_DEBUG_STARTUP,
02703 "Setting initial window workspace to %d based on startup info\n",
02704 space);
02705
02706 window->initial_workspace_set = TRUE;
02707 window->initial_workspace = space;
02708 changed_something = TRUE;
02709 }
02710 }
02711
02712 if (!window->initial_timestamp_set)
02713 {
02714 guint32 timestamp = sn_startup_sequence_get_timestamp (sequence);
02715 meta_topic (META_DEBUG_STARTUP,
02716 "Setting initial window timestamp to %u based on startup info\n",
02717 timestamp);
02718
02719 window->initial_timestamp_set = TRUE;
02720 window->initial_timestamp = timestamp;
02721 changed_something = TRUE;
02722 }
02723
02724 return changed_something;
02725 }
02726 else
02727 {
02728 meta_topic (META_DEBUG_STARTUP,
02729 "Did not find startup sequence for window %s ID \"%s\"\n",
02730 window->desc, startup_id);
02731 }
02732
02733 #endif
02734
02735 return FALSE;
02736 }
02737
02738 int
02739 meta_screen_get_screen_number (MetaScreen *screen)
02740 {
02741 return screen->number;
02742 }
02743
02744 MetaDisplay *
02745 meta_screen_get_display (MetaScreen *screen)
02746 {
02747 return screen->display;
02748 }
02749
02750 Window
02751 meta_screen_get_xroot (MetaScreen *screen)
02752 {
02753 return screen->xroot;
02754 }
02755
02756 void
02757 meta_screen_get_size (MetaScreen *screen,
02758 int *width,
02759 int *height)
02760 {
02761 *width = screen->rect.width;
02762 *height = screen->rect.height;
02763 }
02764
02765 gpointer
02766 meta_screen_get_compositor_data (MetaScreen *screen)
02767 {
02768 return screen->compositor_data;
02769 }
02770
02771 void
02772 meta_screen_set_compositor_data (MetaScreen *screen,
02773 gpointer compositor)
02774 {
02775 screen->compositor_data = compositor;
02776 }
02777
02778 #ifdef HAVE_COMPOSITE_EXTENSIONS
02779 void
02780 meta_screen_set_cm_selection (MetaScreen *screen)
02781 {
02782 char selection[32];
02783 Atom a;
02784
02785 g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
02786 meta_verbose ("Setting selection: %s\n", selection);
02787 a = XInternAtom (screen->display->xdisplay, selection, FALSE);
02788 XSetSelectionOwner (screen->display->xdisplay, a,
02789 screen->wm_cm_selection_window, CurrentTime);
02790 }
02791
02792 void
02793 meta_screen_unset_cm_selection (MetaScreen *screen)
02794 {
02795 char selection[32];
02796 Atom a;
02797
02798 g_snprintf (selection, sizeof(selection), "_NET_WM_CM_S%d", screen->number);
02799 a = XInternAtom (screen->display->xdisplay, selection, FALSE);
02800 XSetSelectionOwner (screen->display->xdisplay, a, None, CurrentTime);
02801 }
02802 #endif