/** @brief Creates the mode menu which can be used by all windows in all workspaces. The main even loop uses the windows and events to determine if a mode menu item was clicked or interacted with in some way. @return void **/ void create_mode_menu(Display *display, struct Mode_menu *mode_menu , struct Themes *themes, struct Cursors *cursors) { Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); mode_menu->menu.inner_width = DEFAULT_MENU_ITEM_WIDTH; mode_menu->menu.inner_height = themes->popup_menu[menu_item_mid].h * (hidden + 1); create_popup_menu(display, &mode_menu->menu, themes, cursors); //Create the menu items for(int i = 0; i <= hidden; i++) { mode_menu->items[i].item = XCreateSimpleWindow(display, mode_menu->menu.widgets[popup_menu_parent].widget , themes->popup_menu[popup_l_edge].w, themes->popup_menu[popup_t_edge].h + themes->popup_menu[menu_item_mid].h * i , mode_menu->menu.inner_width, themes->popup_menu[menu_item_mid].h, 0, black, black); XSelectInput(display, mode_menu->items[i].item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); for(int j = 0; j <= inactive; j++) { if(themes->popup_menu[i].state_p[j]) { char *label = NULL; char Floating[] = "Floating"; char Tiling[] = "Tiling"; char Hidden[] = "Hidden"; char Desktop[] = "Desktop"; switch(i) { case floating: label = Floating; break; case tiling: label = Tiling; break; case hidden: label = Hidden; break; case desktop: label = Desktop; break; } mode_menu->items[i].state[j] = XCreateSimpleWindow(display, mode_menu->items[i].item , 0, 0, mode_menu->menu.inner_width, themes->popup_menu[menu_item_mid].h, 0, black, black); create_text_background(display, mode_menu->items[i].state[j], label, &themes->font_theme[j] , themes->popup_menu[menu_item_mid].state_p[j] , themes->popup_menu[menu_item_mid].w, themes->popup_menu[menu_item_mid].h); XMapWindow(display, mode_menu->items[i].state[j]); } // else printf("Warning: Skipping state pixmap\n"); } XMapWindow(display, mode_menu->items[i].item); } }
/** @pre display is valid, menubar is not null but not initialized, seps is valid, themes is valid, cursors is valid. @post Menubar created and mapped. @brief This function uses the menubar member of the themes pointer to generate all the windows that comprise the menubar with appropriate pixmap backgrounds. @todo Possibly have an extra parameter that determines whether the menubar is a popup menu and use the shape extention. @return void **/ void create_menubar(Display *display, struct Menubar *menubar, struct Separators *seps, struct Themes *themes, struct Cursors *cursors) { /* create new window structure, using theme pixmaps */ XSetWindowAttributes set_attributes; Window root = DefaultRootWindow(display); Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); unsigned int spacing; spacing = (XWidthOfScreen(screen) - themes->menubar[program_menu].w )/4; menubar->widgets[menubar_parent].widget = XCreateSimpleWindow(display, root , 0, XHeightOfScreen(screen) - themes->menubar[menubar_parent].h, XWidthOfScreen(screen) , themes->menubar[menubar_parent].h, 0, black, black); xcheck_setpixmap(display, menubar->widgets[menubar_parent].widget , themes->menubar[menubar_parent].state_p[normal]); for(int i = 0; i < menubar_parent; i++) { menubar->widgets[i].widget = XCreateSimpleWindow(display, menubar->widgets[menubar_parent].widget , spacing*i, 0, themes->menubar[i].w, themes->menubar[i].h, 0, black, black); XSelectInput(display, menubar->widgets[i].widget, Button1MotionMask | ButtonPressMask | ButtonReleaseMask); XDefineCursor(display, menubar->widgets[i].widget, cursors->pressable); for(int j = 0; j <= inactive; j++) { if(themes->menubar[i].state_p[j]) { menubar->widgets[i].state[j] = XCreateSimpleWindow(display, menubar->widgets[i].widget , 0, 0, themes->menubar[i].w, themes->menubar[i].h, 0, black, black); char *label = NULL; char Program[] = "Program"; char Window[] = "Window"; char Options[] = "Options"; char Links[] = "Links"; char Tool[] = "Tool"; switch(i) { case program_menu: label = Program; break; case window_menu: label = Window; break; case options_menu: label = Options; break; case links_menu: label = Links; break; case tool_menu: label = Tool; break; } if(label) { create_text_background(display, menubar->widgets[i].state[j], label , &themes->font_theme[j], themes->menubar[i].state_p[j] , themes->menubar[i].w, themes->menubar[i].h); } else { xcheck_setpixmap(display, menubar->widgets[i].state[j], themes->menubar[i].state_p[j]); } xcheck_map(display, menubar->widgets[i].state[j]); } //else printf("Warning: Skipping state pixmap\n"); } xcheck_map(display, menubar->widgets[i].widget); } set_attributes.override_redirect = True; XChangeWindowAttributes(display, menubar->widgets[menubar_parent].widget , CWOverrideRedirect, &set_attributes); { XWindowChanges changes; unsigned int mask = CWSibling | CWStackMode; changes.stack_mode = Below; changes.sibling = seps->panel_separator; XConfigureWindow(display, menubar->widgets[menubar_parent].widget, mask, &changes); } /* Show initial state. */ xcheck_raisewin(display, menubar->widgets[program_menu].state[normal]); xcheck_raisewin(display, menubar->widgets[window_menu].state[normal]); XFlush(display); /* Show everything */ XMapWindow(display, menubar->widgets[menubar_parent].widget); XFlush(display); }
/** @brief Creates a new workspace, including separators used for stacking windows in different modes and the workspace menu item for the program menu. @return the index of the created workspace **/ int create_workspace(Display *display, struct Workspace_list* workspaces, char *workspace_name, struct Themes *themes) { // Window root = DefaultRootWindow(display); Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); // XSetWindowAttributes attributes; struct Workspace *frames; if(workspaces->list == NULL) { workspaces->used_workspaces = 0; workspaces->max_workspaces = 16; workspaces->list = malloc(sizeof(struct Workspace) * workspaces->max_workspaces); if(workspaces->list == NULL) return -1; } else if(workspaces->used_workspaces == workspaces->max_workspaces) { //printf("reallocating, used_workspaces %d, max%d\n", workspaces->used_workspaces, workspaces->max); struct Workspace* temp = NULL; temp = realloc(workspaces->list, sizeof(struct Workspace) * workspaces->max_workspaces * 2); if(temp != NULL) workspaces->list = temp; else { perror("\nError: Not enough available memory\n"); return -1; } workspaces->max_workspaces *= 2; } //the frame list frames is the new workspace frames = &workspaces->list[workspaces->used_workspaces]; frames->workspace_name = workspace_name; frames->states = calloc(sizeof(struct Saved_frame_state), workspaces->max_frames); if(!frames->states) { perror("Error: not enough memory to allocate frame save states in a new workspace"); return -1; } //TODO when a workspace is added to the list, it must also be resized to the width of that list. unsigned int width = workspaces->workspace_menu.inner_width; frames->workspace_menu.item = XCreateSimpleWindow(display , workspaces->workspace_menu.widgets[popup_menu_parent].widget , themes->popup_menu[popup_l_edge].w, themes->popup_menu[popup_t_edge].h , width, themes->popup_menu[menu_item_mid].h , 0, black, black); XSelectInput(display, frames->workspace_menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); for(int i = 0; i <= inactive; i++) { //if(themes->popup_menu[menu_item].state_p[i]) frames->workspace_menu.state[i] = XCreateSimpleWindow(display , frames->workspace_menu.item , 0, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); create_text_background(display, frames->workspace_menu.state[i], frames->workspace_name , &themes->font_theme[i], themes->popup_menu[menu_item_mid].state_p[i] , themes->popup_menu[menu_item_mid].w, themes->popup_menu[menu_item_mid].h); XMapWindow(display, frames->workspace_menu.state[i]); } XMapWindow(display, frames->workspace_menu.item); frames->workspace_menu.width = get_text_width(display, frames->workspace_name, &themes->font_theme[active]); //Create the frame_list frames->used = 0; frames->max = DEFAULT_STARTING_FRAMES; frames->list = NULL; //this is allocated when we change to this workspace. frames->focus.used = 0; frames->focus.max = 8; //must be divisible by 2 frames->focus.list = malloc(sizeof(struct Focus_list) * frames->focus.max); //ok if it fails. #ifdef SHOW_WORKSPACE printf("Created workspace %d\n", workspaces->used_workspaces); #endif //need to make the existing neutral windows available to new workspaces for(int i = 0; i < workspaces->used_frames; i++) { if(suitable_for_foreign_workspaces(&workspaces->frame_list[i])) { load_initial_states(&frames->states[i], &workspaces->frame_list[i]); } } workspaces->used_workspaces++; XSync(display, False); return workspaces->used_workspaces - 1; }
/** @brief create pixmaps with the specified name if it is available, otherwise use a default name @return void **/ void create_frame_name(Display* display, struct Popup_menu *window_menu, struct Frame *temp , struct Themes *themes, struct Atoms *atoms) { char untitled[] = "noname"; //struct Frame temp = *frame; Screen* screen = DefaultScreenOfDisplay(display); int black = BlackPixelOfScreen(screen); /* Destroy/Free old title if it had one */ free_frame_name(temp); { /* Recover EWMH UTF8 name first. If none exists, get the ICCCM ASCII name */ /* If this succeeds, previous names will be freed if they exists later on */ Atom ret_type; int ret_format; unsigned long ret_nitems; unsigned long ret_trailing_bytes; temp->window_name = NULL; if((XGetWindowProperty (display, temp->framed_window, atoms->name, (long)0, (long)MAX_WM_NAME_LENGTH , False, atoms->utf8 , &ret_type, &ret_format, &ret_nitems, &ret_trailing_bytes , (unsigned char **)&temp->window_name ) != Success) || temp->window_name == NULL) { //Try and get the non EWMH name if(!XFetchName(display, temp->framed_window, &temp->window_name)) { //Generate a blank name. printf("Warning: unnamed window\n"); XStoreName(display, temp->framed_window, untitled); XFlush(display); XFetchName(display, temp->framed_window, &temp->window_name); XFlush(display); } } } /* if(temp->window_name == NULL && frame->window_name != NULL && strcmp(frame->window_name, untitled) == 0) { //it was null and already has the name from untitled above. return; } else if( (temp->window_name != NULL && frame->window_name != NULL ) && (strcmp(temp->window_name, frame->window_name) == 0)) { XFree(temp->window_name); //skip this if the name hasn't changed return; } */ if(!temp->menu.item) { temp->menu.item = XCreateSimpleWindow(display , window_menu->widgets[popup_menu_parent].widget , themes->popup_menu[l_edge].w, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); for(int i = 0; i <= inactive; i++) { temp->menu.state[i] = XCreateSimpleWindow(display , temp->menu.item , 0, 0 , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h , 0, black, black); } XSelectInput(display, temp->menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); } temp->menu.width = get_text_width(display, temp->window_name, &themes->font_theme[active]); //create corresponding title menu item for this frame for(int i = 0; i <= inactive; i++) { XUnmapWindow(display, temp->menu.state[i]); XUnmapWindow(display, temp->widgets[title_menu_text].state[i]); XFlush(display); //create the title menu item with the windows title create_text_background(display, temp->menu.state[i], temp->window_name , &themes->font_theme[i], themes->popup_menu[menu_item_mid].state_p[i] , XWidthOfScreen(screen), themes->popup_menu[menu_item_mid].h); //TODO make the title for unfocussed windows not bold? create_text_background(display, temp->widgets[title_menu_text].state[i], temp->window_name , &themes->font_theme[active], themes->window_type[temp->theme_type][title_menu_text].state_p[i] , XWidthOfScreen(screen), themes->window_type[temp->theme_type][title_menu_text].h); //If this is mapped here, it might be shown in the wrong workspace, //XMapWindow(display, temp->menu.item); /* Show changes to background pixmaps */ XMapWindow(display, temp->menu.state[i]); XMapWindow(display, temp->widgets[title_menu_text].state[i]); } xcheck_raisewin(display, temp->menu.state[active]); //these are the items for inside the menu //need to create all these windows. { XWindowAttributes attr; XGetWindowAttributes(display, temp->menu.item, &attr); if(attr.map_state != IsUnmapped) { //remap all the state pixmaps XSelectInput(display, temp->menu.item, 0); XSync(display, False); XUnmapWindow(display, temp->menu.item); XSelectInput(display, temp->menu.item, ButtonReleaseMask | EnterWindowMask | LeaveWindowMask); XFlush(display); XMapWindow(display, temp->menu.item); } } XFlush(display); //*frame = temp; }